国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

當前位置:雨林木風下載站 > 技術開發教程 > 詳細頁面

數據庫查詢結果的動態排序

數據庫查詢結果的動態排序

更新時間:2022-05-07 文章作者:未知 信息來源:網絡 閱讀次數:

在公共新聞組中,一個經常出現的問題是“怎樣才能根據傳遞給存儲過程的參數返回一個排序的輸出?”。在一些高水平專家的幫助之下,我整理出了這個問題的幾種解決方案。

一、用IF...ELSE執行預先編寫好的查詢


  對于大多數人來說,首先想到的做法也許是:通過IF...ELSE語句,執行幾個預先編寫好的查詢中的一個。例如,假設要從Northwind數據庫查詢得到一個貨主(Shipper)的排序列表,發出調用的代碼以存儲過程參數的形式指定一個列,存儲過程根據這個列排序輸出結果。Listing 1顯示了這種存儲過程的一個可能的實現(GetSortedShippers存儲過程)。


【Listing 1: 用IF...ELSE執行多個預先編寫好的查詢中的一個】


CREATE PROC GetSortedShippers

@OrdSeq AS int

AS


IF @OrdSeq = 1

SELECT * FROM Shippers ORDER BY ShipperID

ELSE IF @OrdSeq = 2

SELECT * FROM Shippers ORDER BY CompanyName

ELSE IF @OrdSeq = 3

SELECT * FROM Shippers ORDER BY Phone



  這種方法的優點是代碼很簡單、很容易理解,SQL Server的查詢優化器能夠為每一個SELECT查詢創建一個查詢優化計劃,確保代碼具有最優的性能。這種方法最主要的缺點是,如果查詢的要求發生了改變,你必須修改多個獨立的SELECT查詢——在這里是三個。


二、用列名字作為參數

  另外一個選擇是讓查詢以參數的形式接收一個列名字。Listing 2顯示了修改后的GetSortedShippers存儲過程。CASE表達式根據接收到的參數,確定SQL Server在ORDER BY子句中使用哪一個列值。注意,ORDER BY子句中的表達式并未在SELECT清單中出現。在ANSI SQL-92標準中,ORDER BY子句中不允許出現沒有在SELECT清單中指定的表達式,但ANSI SQL-99標準允許。SQL Server一直允許這種用法。


【Listing 2:用列名字作為參數,第一次嘗試】


CREATE PROC GetSortedShippers

@ColName AS sysname

AS


SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID' THEN ShipperID

WHEN 'CompanyName' THEN CompanyName

WHEN 'Phone' THEN Phone

ELSE NULL

END



  現在,我們來試一下新的存儲過程,以參數的形式指定ShipperID列:


EXEC GetSortedShippers 'ShipperID'



  此時一切正常。但是,當我們視圖把CompanyName列作為參數調用存儲過程時,它不再有效:


EXEC GetSortedShippers 'CompanyName'



  仔細看一下錯誤信息:


Server: Msg 245, Level 16, State 1, Procedure GetSortedShippers, Line 5

Syntax error converting the nvarchar value 'Speedy

Express' to a column of data type int.



  它顯示出,SQL Server試圖把“Speedy Express”(nvarchar數據類型)轉換成一個整數值——當然,這個操作是不可能成功的。出現錯誤的原因在于,按照“數據類型優先級”規則,CASE表示式中最高優先級的數據類型決定了表達式返回值的數據類型。“數據類型優先級”規則可以在SQL Server Books Online(BOL)找到,它規定了int數據類型的優先級要比nvarchar數據類型高。前面的代碼要求SQL Server按照CompanyName排序輸出,CompanyName是nvarchar數據類型。這個CASE表達式的返回值可能是ShipperID(int類型),可能是CompanyName(nvarchar類型),或Phone(nvarchar類型)。由于int類型具有較高的優先級,因此CASE表達式返回值的數據類型應該是int。


為了避免出現這種轉換錯誤,我們可以嘗試把ShipperID轉換成varchar數據類型。采用這種方法之后,nvarchar將作為最高優先級的數據類型被返回。Listing 3顯示了修改后的GetSortedShippers存儲過程。

【Listing 3:用列名字作為參數,第二次嘗試】


ALTER PROC GetSortedShippers

@ColName AS sysname

AS


SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID'

THEN CAST(ShipperID AS varchar(11))

WHEN 'CompanyName'

THEN CompanyName

WHEN 'Phone'

THEN Phone

ELSE NULL

END



  現在,假設我們再把三個列名字中的任意一個作為參數調用存儲過程,輸出結果看起來正確。看起來就象指定的列正確地為查詢輸出提供了排序標準。但這個表只有三個貨主,它們的ID分別是1、2、3。假設我們把更多的貨主加入到表,如Listing 4所示(ShipperID列有IDENTITY屬性,SQL Server自動為該列生成值)。


【Listing 4:向Shippers表插入一些記錄】


INSERT INTO Shippers VALUES('Shipper4', '(111) 222-9999')

INSERT INTO Shippers VALUES('Shipper5', '(111) 222-8888')

INSERT INTO Shippers VALUES('Shipper6', '(111) 222-7777')

INSERT INTO Shippers VALUES('Shipper7', '(111) 222-6666')

INSERT INTO Shippers VALUES('Shipper8', '(111) 222-5555')

INSERT INTO Shippers VALUES('Shipper9', '(111) 222-4444')

INSERT INTO Shippers VALUES('Shipper10', '(111) 222-3333')



  現在調用存儲過程,指定ShipperID作為排序列:


EXEC GetSortedShippers 'ShipperID'



  表一顯示了存儲過程的輸出。ShipperID等于10的記錄位置錯誤,因為這個存儲過程的排序輸出是字符排序,而不是整數排序。按照字符排序時,10排列在2的前面,因為10的開始字符是1。


表一:記錄排序錯誤的查詢結果


ShipperID CompanyName Phone

1 Speedy Express (503) 555-9831

10 Shipper10 (111) 222-3333

2 United Package (503) 555-3199

3 Federal Shipping (503) 555-9931

4 Shipper4 (111) 222-9999

5 Shipper5 (111) 222-8888

6 Shipper6 (111) 222-7777

7 Shipper7 (111) 222-6666

8 Shipper8 (111) 222-5555

9 Shipper9 (111) 222-4444


為了解決這個問題,我們可以用前置的0補足ShipperID值,使得ShipperID值都有同樣的長度。按照這種方法,基于字符的排序具有和整數排序同樣的輸出結果。修改后的存儲過程如Listing 5所示。十個0被置于ShipperID的絕對值之前,而在結果中,代碼只是使用最右邊的10個字符。SIGN函數確定在正數的前面加上加號(+)前綴,還是在負數的前面加上負號(-)前綴。按照這種方法,輸出結果總是有11個字符,包含一個“+”或“-”字符、前導的字符0以及ShipperID的絕對值。

【Listing 5:用列名字作為參數,第三次嘗試】


ALTER PROC GetSortedShippers

@ColName AS sysname

AS


SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID' THEN CASE SIGN(ShipperID)

WHEN -1 THEN '-'

WHEN 0 THEN '+'

WHEN 1 THEN '+'

ELSE NULL

END +

RIGHT(REPLICATE('0', 10) +

CAST(ABS(ShipperID) AS varchar(10)), 10)

WHEN 'CompanyName' THEN CompanyName

WHEN 'Phone' THEN Phone

ELSE NULL

END



  如果ShipperID的值都是正數,加上符號前綴就沒有必要,但為了讓方案適用于盡可能多的范圍,本例加上了符號前綴。排序時“-”在“+”的前面,所以它可以用于正、負數混雜排序的情況。


  現在,如果我們用任意三個列名字之一作為參數調用存儲過程,存儲過程都能夠正確地返回結果。Richard Romley提出了一種巧妙的處理方法,如Listing 6所示。它不再要求我們搞清楚可能涉及的列數據類型。這種方法把ORDER BY子句分成三個獨立的CASE表達式,每一個表達式處理一個不同的列,避免了由于CASE只返回一種特定數據類型的能力而導致的問題。


【Listing 6:用列名字作為參數,Romley提出的方法】


ALTER PROC GetSortedShippers

@ColName AS sysname

AS


SELECT *

FROM Shippers

ORDER BY

CASE @ColName WHEN 'ShipperID'

THEN ShipperID ELSE NULL END,

CASE @ColName WHEN 'CompanyName'

THEN CompanyName ELSE NULL END,

CASE @ColName WHEN 'Phone'

THEN Phone ELSE NULL END



  按照這種方法編寫代碼,SQL Server能夠為每一個CASE表達式返回恰當的數據類型,而且無需進行數據類型轉換。但應該注意的是,只有當指定的列不需要進行計算時,索引才能夠優化排序操作。


三、用列號作為參數

  就象第一個方案所顯示地那樣,你也許更喜歡用列的編號作為參數,而不是使用列的名字(列的編號即一個代表你想要作為排序依據的列的數字)。這種方法的基本思想與使用列名字作為參數的思想一樣:CASE表達式根據指定的列號確定使用哪一個列進行排序。Listing 7顯示了修改后的GetSortedShippers存儲過程。


【Listing 7:用列號作為參數】


ALTER PROC GetSortedShippers

@ColNumber AS int

AS


SELECT *

FROM Shippers

ORDER BY

CASE @ColNumber

WHEN 1 THEN CASE SIGN(ShipperID)

WHEN -1 THEN '-'

WHEN 0 THEN '+'

WHEN 1 THEN '+'

ELSE NULL

END +

RIGHT(REPLICATE('0', 10) +

CAST(ABS(ShipperID) AS varchar(10)), 10)

WHEN 2 THEN CompanyName

WHEN 3 THEN Phone

ELSE NULL

END



  當然,在這里你也可以使用Richard的方法,避免ORDER BY子句中列數據類型帶來的問題。如果要根據ShipperID排序輸出,你可以按照下面的方式調用修改后的GetSortedShippers存儲過程:


EXEC GetSortedShippers 1


四、動態執行

  使用動態執行技術,我們能夠更輕松地編寫出GetSortedShippers存儲過程。使用這種方法時,我們只需動態地構造出SELECT語句,然后用EXEC()命令執行這個SELECT語句。假設傳遞給存儲過程的參數是列的名字,存儲過程可以大大縮短:


ALTER PROC GetSortedShippers

@ColName AS sysname

AS

EXEC('SELECT * FROM Shippers ORDER BY ' +

@ColName)



  在SQL Server 2000和7.0中,你可以用系統存儲過程sp_ExecuteSQL替代Exec()命令。BOL說明了使用sp_ExecuteSQL比使用Exec()命令更有利的地方。一般地,如果滿足以下三個條件,你能夠在不授予存儲過程所涉及對象權限的情況下,授予執行存儲過程的權限:首先,只使用Data Manipulation Language(DML)語言(即SELECT,INSERT,UPDATE,DELETE);其次,所有被引用的對象都有與存儲過程同樣的所有者;第三,沒有使用動態命令。


  上面的存儲過程不能滿足第三個條件。在這種情況下,你必須為所有需要使用存儲過程的用戶和組顯式地授予Shippers表的SELECT權限。如果這一點可以接受的話,一切不存在問題。類似地,你可以修改存儲過程,使它接受一個列號參數,如Listing 8所示。


【Listing 8:用列號作為參數,動態執行(代碼較長的方法)】


ALTER PROC GetSortedShippers

@ColNumber AS int

AS


DECLARE @cmd AS varchar(8000)


SET @cmd = 'SELECT * FROM Shippers ORDER BY ' +

CASE @ColNumber

WHEN 1 THEN 'ShipperID'

WHEN 2 THEN 'CompanyName'

WHEN 3 THEN 'Phone'

ELSE 'NULL'

END


EXEC(@cmd)



  注意,當你使用了函數時,你應該在一個變量而不是EXEC()命令內構造SELECT語句。此時,CASE表達式動態地確定使用哪一個列。還有一種更簡短的格式,T-SQL允許在ORDER BY子句中指定SELECT清單中列的位置,如Listing 9所示。這種格式遵從了SQL-92標準,但ANSI SQL-99標準不支持這種格式,所以最好不要使用這種格式。


【Listing 9:列號作為參數,動態執行(代碼較短的方法)】


ALTER PROC GetSortedShippers

@ColNumber AS int

AS

DECLARE @cmd AS varchar(8000)

SET @cmd = 'SELECT * FROM Shippers ORDER BY ' + CAST(@ColNumber AS varchar(4))


EXEC(@cmd)


五、用戶定義函數

  如果你使用的是SQL Server 2000,想要編寫一個用戶定義的函數(UDF),這個用戶定義函數接受列的名字或編號為參數、返回排序的結果集,Listing 10顯示了大多數程序員當成第一選擇的方法。


【Listing 10:列名字作為參數,使用UDF】


CREATE FUNCTION ufn_GetSortedShippers

(

@ColName AS sysname

)

RETURNS TABLE

AS


RETURN

SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID' THEN CASE SIGN(ShipperID)

WHEN -1 THEN '-'

WHEN 0 THEN '+'

WHEN 1 THEN '+'

ELSE NULL

END +

RIGHT(REPLICATE('0', 10) +

CAST(ABS(ShipperID) AS

varchar(10)), 10)

WHEN 'CompanyName' THEN CompanyName

WHEN 'Phone' THEN Phone

ELSE NULL

END



  但是,SQL Server不接受這個函數,它將返回如下錯誤信息:


Server: Msg 1033, Level 15, State 1, Procedure ufn_GetSortedShippers,

Line 24

The ORDER BY clause is invalid in views, inline functions, and

subqueries, unless TOP is also specified.



  注意錯誤信息中的“unless”。SQL Server 2000不允許在視圖、嵌入式UDF、子查詢中出現ORDER BY子句,因為它們都應該返回一個表,表不能指定行的次序。然而,如果使用了TOP關鍵詞,ORDER BY子句將幫助確定查詢所返回的行。因此,如果指定了TOP,你還可以同時指定ORDER BY。由于在帶有TOP的UDF中允許使用ORDER BY子句,你可以使用一個技巧:把“SELECT *”替換成“SELECT TOP 100 PERCENT *”。這樣,你就能夠成功地構造出一個接受列名字或編號為參數、返回排序結果的函數。


  新構造的函數可以按照如下方式調用:


SELECT * FROM ufn_GetSortedShippers('ShipperID')



  現在,你已經了解了幾種用參數確定查詢輸出中記錄次序的方法。在編寫那些允許用戶指定查詢結果排序標準的列的應用程序時,你可以使用本文介紹的各種技術,用列名字或編號作為參數,構造出使用CASE表達式和動態執行能力的各種方案。

溫馨提示:喜歡本站的話,請收藏一下本站!

本類教程下載

系統下載排行

国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

  • <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        菠萝蜜视频在线观看一区| 欧美不卡视频一区| 日韩女优制服丝袜电影| 国产精品一色哟哟哟| 成人免费的视频| 欧美在线观看禁18| 日韩欧美综合在线| 久久午夜国产精品| 亚洲免费伊人电影| 不卡视频一二三| 久久精品亚洲国产奇米99| 琪琪一区二区三区| 国产三级一区二区| 欧美日韩国产精品成人| 一本大道久久精品懂色aⅴ | 91蜜桃在线免费视频| 欧美日韩在线一区二区| 欧洲人成人精品| 日韩一区二区三区观看| 国产欧美日韩综合精品一区二区| 国产精品电影院| 亚洲第一会所有码转帖| 国产精品一区在线观看你懂的| 成人黄色片在线观看| 欧美特级限制片免费在线观看| 亚洲精品一区二区三区在线观看 | 麻豆成人av在线| 国产91精品露脸国语对白| 欧美日韩色综合| 国产午夜精品美女毛片视频| 亚洲国产欧美在线| 99久久精品国产麻豆演员表| 国产亚洲美州欧州综合国| 美女国产一区二区三区| 欧美丝袜丝交足nylons图片| 国产日韩成人精品| 裸体在线国模精品偷拍| 欧美日韩午夜在线| 亚洲一区二区三区精品在线| youjizz久久| 国产婷婷色一区二区三区在线| 蜜臀国产一区二区三区在线播放 | 国产精品久久久久久久久图文区| 美腿丝袜亚洲一区| 欧美最新大片在线看| 国产精品沙发午睡系列990531| 免费视频最近日韩| 在线成人免费观看| 亚洲电影视频在线| 欧美日韩在线一区二区| 久久国产福利国产秒拍| 在线播放/欧美激情| 日精品一区二区三区| 欧美美女黄视频| 丝瓜av网站精品一区二区| 欧美丝袜自拍制服另类| 日本亚洲天堂网| 久久综合网色—综合色88| 国产一区二区剧情av在线| 精品裸体舞一区二区三区| 国产乱子伦视频一区二区三区 | 欧美大胆人体bbbb| 国产麻豆一精品一av一免费| 久久久国产精品午夜一区ai换脸| 国产盗摄一区二区| 综合久久国产九一剧情麻豆| 91国产精品成人| 另类小说一区二区三区| 国产精品色噜噜| 在线免费精品视频| 精品一区二区三区的国产在线播放| 精品精品国产高清a毛片牛牛| 国产精品综合视频| 亚洲女女做受ⅹxx高潮| 97精品视频在线观看自产线路二| 国产精品一区专区| 亚洲国产精品av| 91网站最新网址| 丝袜亚洲精品中文字幕一区| 国产69精品久久777的优势| 中文一区一区三区高中清不卡| 成人免费视频一区| 一区二区三区四区不卡在线| 欧美一区二区性放荡片| 免费一级欧美片在线观看| 国产午夜一区二区三区| 日本道精品一区二区三区| 亚洲午夜av在线| 欧美一级片在线观看| 成人av在线影院| 午夜一区二区三区视频| 国产欧美精品在线观看| 一本久久a久久精品亚洲| 久草热8精品视频在线观看| 亚洲视频1区2区| 制服.丝袜.亚洲.另类.中文| 国产精品18久久久久久久久| 欧美国产视频在线| 69p69国产精品| 欧美一级二级三级乱码| 自拍偷拍亚洲欧美日韩| 色婷婷av一区二区三区gif| 水蜜桃久久夜色精品一区的特点 | 国产成人亚洲精品青草天美| 国产精品家庭影院| 日韩精品一区二区三区在线| 欧美在线看片a免费观看| 麻豆高清免费国产一区| 自拍偷拍欧美激情| 精品99久久久久久| 欧美日韩精品三区| 91丝袜美腿高跟国产极品老师| 国产一区高清在线| 欧美嫩在线观看| 91在线观看成人| 丁香婷婷综合激情五月色| 日韩 欧美一区二区三区| 亚洲一区成人在线| 综合在线观看色| 中文字幕第一页久久| 精品国产乱码久久久久久老虎 | 粉嫩av亚洲一区二区图片| 美国三级日本三级久久99| 亚洲高清不卡在线| 亚洲男女一区二区三区| 亚洲欧美福利一区二区| 国产精品日韩成人| 亚洲私人影院在线观看| 综合久久国产九一剧情麻豆| 久久久久久久精| 久久精品人人做人人综合| 精品国产百合女同互慰| 久久综合久久综合久久| 日韩一级视频免费观看在线| 日韩欧美成人一区二区| 精品欧美一区二区在线观看| 日韩一本二本av| 国产亚洲欧美中文| 中文乱码免费一区二区| 国产精品青草综合久久久久99| 国产精品不卡一区二区三区| 亚洲精品免费在线| 日韩和欧美的一区| 日本不卡不码高清免费观看| 精品一区二区免费在线观看| 国产一区二区0| 99久久伊人久久99| 欧美日韩免费在线视频| 欧美一区二区视频在线观看| 欧美精品一区二区三区视频| 久久先锋影音av| 一区二区在线观看免费| 蜜臀久久99精品久久久画质超高清| 国产精品一区二区久激情瑜伽 | 成人av手机在线观看| 欧美综合视频在线观看| 欧美xxxx老人做受| 国产精品色呦呦| 日韩精品免费视频人成| www.日韩精品| 日韩欧美的一区| 亚洲另类一区二区| 国产精品99久久久久久似苏梦涵| 91黄色免费观看| 国产日产欧美精品一区二区三区| 亚洲高清不卡在线观看| av在线不卡电影| 精品国产麻豆免费人成网站| 一区二区三区美女| 国产91综合网| 日韩限制级电影在线观看| 一区二区在线观看视频| 成人午夜av在线| 日韩一区二区在线免费观看| 亚洲蜜臀av乱码久久精品| 韩国理伦片一区二区三区在线播放| 91丨国产丨九色丨pron| 国产欧美一区二区精品性色 | 裸体健美xxxx欧美裸体表演| av在线播放一区二区三区| 26uuu国产日韩综合| 奇米精品一区二区三区在线观看一| 成人动漫一区二区在线| 欧美精品一区二区三区高清aⅴ | 欧美三级乱人伦电影| 欧美—级在线免费片| 免费高清在线一区| 欧美日韩和欧美的一区二区| 一区二区三区精品在线| 色综合久久中文综合久久97| 亚洲成av人片www| av成人动漫在线观看| 日韩免费观看2025年上映的电影| 亚洲综合激情另类小说区| av在线不卡免费看| 中文字幕一区二区三区乱码在线| 粉嫩欧美一区二区三区高清影视 | 亚洲电影激情视频网站| 欧美亚洲国产怡红院影院| 亚洲国产成人91porn|