1. 程式人生 > >解決SQL Server查詢中使用Union或Union All後Order by排序無效的bug(好神奇啊!!)

解決SQL Server查詢中使用Union或Union All後Order by排序無效的bug(好神奇啊!!)

http://www.ourcodelife.com/article-415-1.html

首先,在程式人生網站上,需要負責任的指出的是在SQL Server查詢中使用Union或Union All後Order by排序無效,我不確認是不是微軟的bug,不過這裡卻是我實際程式設計工作的經驗,但願大家看到這篇文章後,不要再走彎路,不要再為做一個快樂的程式設計師而苦惱。

下面以可操作性的程式碼說明這個bug,權且先認為是bug吧。

比如有一張學生表student 和教師表 teacher , 我們要查詢所有的教師學生的姓名和年齡,教師排前面,學生排後面,分別按字母順序,則可能會想寫一個這樣的Sql語句: (注意,這個語句只是為了說明問題,這並不是一個正確的語句)

SELECT Name,Age FROM Teacher ORDER BY Name 
UNION 
SELECT Name,Age FROM Student ORDER BY Name

實際上,MSSQL並不允許我們寫這樣的語句,因此將會報錯 UNION 附近有語法錯誤.

其實我們只需要繞開,讓ORDER BY 和UNION 不在同一層, 讓ORDER 在子查詢內而 UNION 在外面(因為我們要先教師學生分開,然後再名字) 這樣得到了另外一個Sql語句:(注意,這依然不是一個正確的語句)

SELECT * FROM (SELECT Name,Age FROM Teacher ORDER BY Name) A 
UNION 
SELECT * FROM (SELECT Name,Age FROM Student ORDER BY Name) B

這句Sql語句依然無法通過,因為這又觸犯了MSSQL的另外一條語法規定,在子查詢中, 如果不存在TOP語句則ORDER BY子句無效. 但是我們需要的是全部結果,並不需要TOP的功能. 顯然, TOP 100% 是個解決的方法. 因為100%就是全部了.

最後,這條蹩腳的Sql語句出爐了:

SELECT * FROM (SELECT TOP 100 PERCENT Name,Age FROM Teacher ORDER BY Name) A 
UNION 
SELECT * FROM (SELECTTOP 100 PERCENT Name,Age FROM Student ORDER BY Name) B

這就是最後的結果, 為了讓ORDER BY 和UNION同時發揮作用,繞了2個彎.

如果想Union前面和後面的集合分開,使用Union all,但要去除重複的記錄。

但是在使用Union All的時候需要特別注意,在使用Union All的時候,上面講到的規則,也就是Order by 仍然會失效。

讓程式設計師朋友們又苦惱了吧,下面的解決方法就是重點了。

Select TOP 99.999999 PERCENT Name,Age FROM Teacher ORDER BY Name

在使用了99.999999這個特殊數字後,該問題最終得到解決 ,真是神奇啊。

另外補充一點:UNION和UNION ALL的區別 ,UNION在進行錶鏈接後會篩選掉重複的記錄,所以在錶鏈接後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。(應該就是這種演算法讓程式設計師自己編碼的Order by排序失效了)。

UNION ALL只是簡單的將兩個結果集進行連結返回,所以如果我們只是為了連結兩個結果集,只要用UNION ALL就可以了,並且從效率上來說UNION ALL也比UNION快,因為它不需要進行篩選排重的。