SQL-3標準中提供了三種對檢索結果進行集合運算的命令:並集UNION;交集INTERSECT;差集EXCEPT(在Oracle中叫作 MINUS)。在有些數據庫中對此的支持不夠充分,如MySql中只有UNION,沒有其餘兩種。實際上這些運算均可以經過普通的SQL來實現,雖然有時有些繁瑣。mysql
假設有兩個表(或視圖)s,t,s中有兩個字段sa,sb;t中有兩個字段ta,tb;sql
PLAIN TEXT數據庫
SQL:
spa
SELECTsaFROMsorm
EXCEPTget
SELECTtaFROMt;it
能夠寫做io
PLAIN TEXT技巧
SQL:
語法
SELECTsaFROMs
WHEREsaNOTIN
(SELECTtaFROMt)
上面的例子中忽略了對s和t單獨的條件,這些總能夠加入AND條件完成,或者使用視圖。若是是多個字段比較麻煩,如:
PLAIN TEXT
SQL:
SELECTsa, sbFROMs
EXCEPT
SELECTta, tbFROMt;
須要寫成
PLAIN TEXT
SQL:
SELECTsa, sbFROMs
WHERE(sa, sb)NOTIN
(SELECTta, tbFROMt)
上面使用的語法不見得數據庫都支持。好在不支持EXCEPT的MySQL支持這種語法,而不支持這種語法的MSSQL又支持EXCEPT。
注意對於這樣的row constructors(Mysql術語),是和下面寫法(以及其餘相似寫法)不等價的。
PLAIN TEXT
SQL:
SELECTsa, sbFROMs
WHEREsaNOTIN
(SELECTtaFROMt)
ANDsbNOTIN
(SELECTtbFROMt)
在MSSQL中的一個解決技巧是,把這兩個字段(假設字符類型)拼起來,即
PLAIN TEXT
SQL:
SELECTsa, sbFROMs
WHEREsa+sbNOTIN
(SELECTta+tbFROMt)
PLAIN TEXT
SQL:
SELECTsaFROMs
INTERSECT
SELECTtaFROMt;
能夠寫成
PLAIN TEXT
SQL:
SELECTsaFROMs
WHEREsa IN
(SELECTtaFROMt)
固然也能夠寫成
PLAIN TEXT
SQL:
SELECTsaFROMs
WHEREEXISTS
(SELECT*FROMtWHEREt.ta=s.sa)
或者使用鏈接
PLAIN TEXT
SQL:
SELECTsaFROMs, t
WHEREsa = ta
實際上這幾個語句都有點問題,就是INTERSECT在出現重複時的語義問題。按照SQL-3標準,相似UNION,能夠有明確的 INTERSECT ALL或者INTERSECT DISTINCT語法。通常的INTERSECT實現並無明確這一點,並且從邏輯上講意義也不大。那麼當s或t中出現重複的時,如sa='x'的有2 個,sb='x'的有3個,使用上面的子查詢將返回2行,使用鏈接將返回6行,固然這兩個語句均可以加上一個DISTINCT,就實現了 INTERSECT DISTINCT語義了。
MySql從4.0開始就支持UNION(ALL 和 DISTINCT)了,爲完整起見,也列舉一下。
其實實現這樣一個結果是很麻煩的
PLAIN TEXT
SQL:
SELECTsaFROMs
UNIONDISTINCT
SELECTtaFROMt;
須要使用外鏈接,並且是Full的外鏈接
PLAIN TEXT
SQL:
SELECTDISTINCTNVL(s.sa, t.ta)
FROMs FULLOUTERJOINtON(s.sa=t.ta)
上面的例子中我使用了Oracle的語法,實際上MySql不支持FULL OUTER JOIN(雖然支持LEFT和RIGHT OUTER JOIN),好在MySql支持UNION。
對於UNION ALL語義,我尚未想出來用普通查詢如何實現,若是在上面語句中去掉DISTINCT,結果確定不對。