SQL集合操作Union实现
Union的语义是把两部分查询的结果合并起来,最终结果的列名和类型定义与第⼀个查询⼀致。Union语句可以是Union All或者Union Distinct,默认情况下最好采⽤前者,即只有Union关键字时等价于Union All。下⾯看看Union All/Union Distinct的例⼦。
表A      表B
12
34
34
34
56
34
34
78
UnionAll
12
34
34
34
56
34
34
78
UnionDistinct
12
34
56
78
MergeUnion
ALL
如果是Union All,那么MergeUnion的两个输⼊表没有必要是有序的,MergeUnion只需要先输出第⼀个表的数据,再输出第⼆个表的数据就可以了。
Distinct
如果是Union Distinct,MergeUnion算法要求两个输⼊表数据都有相同的排序。假设两个输⼊表的⾏数分别为M、N,则MergeUnion算法复杂度为O(M+N)。
具体实现如下:
1.        如果第⼀个表的当前元组⼩于第⼆个表的当前元组,或者第⼆个表结束,那么输出第⼀个表的元组,且跳过相等的元组。
2.        如果第⼀个表的当前元组⼤于第⼆个表的当前元组,或者第⼀个表结束,那么输出第⼆个表的元组,且跳过相等的元组。
3.        如果第⼀个表的当前元组等于第⼆个表的当前元组,那么输出第⼀个表的元组,且跳过第⼀个和第⼆个表的相同元组。
4        如果两个表都结束,则返回结束。
其余思想类似。前提都是需要排序。不排序,则可以采⽤Hash的思路。思路见
-----
附的⼊门介绍:
SQL-3标准中提供了三种对检索结果进⾏集合运算的命令:并集UNION;交集INTERSECT;差集EXCEPT(在Oracle中叫做 MINUS)。在有些数据库中对此的⽀持不够充分,如中只有UNION,没有其他两种。实际上这些运算都可以通过普通的SQL来实现,虽然有时有些繁琐。
假设有两个表(或视图)s,t,s中有两个字段sa,sb;t中有两个字段ta,tb;
差集EXCEPT:
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. EXCEPT
3. SELECT ta FROM t;
可以写作
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. WHERE sa NOTIN
3. (SELECT ta FROM t)
上⾯的例⼦中忽略了对s和t单独的条件,这些总可以加⼊AND条件完成,或者使⽤视图。如果是多个字段⽐较⿇烦,如:
PLAIN TEXT
SQL:
1. SELECT sa, sb FROM s
2. EXCEPT
3. SELECT ta, tb FROM t;
需要写成
PLAIN TEXT
SQL:
1. SELECT sa, sb FROM s
2. WHERE(sa, sb)NOTIN
3. (SELECT ta, tb FROM t)
上⾯使⽤的语法不见得数据库都⽀持。好在不⽀持EXCEPT的MySQL⽀持这种语法,⽽不⽀持这种语法的MSSQL⼜⽀持EXCEPT。注意对于这样的row constructors(Mysql术语),是和下⾯写法(以及其他类似写法)不等价的。
PLAIN TEXT
SQL:
1. SELECT sa, sb FROM s
2. WHERE sa NOTIN
3. (SELECT ta FROM t)
4. AND sb NOTIN
5. (SELECT tb FROM t)
在MSSQL中的⼀个解决技巧是,把这两个字段(假设字符类型)拼起来,即
PLAIN TEXT
SQL:
1. SELECT sa, sb FROM s
2. WHERE sa+sb NOTIN
3. (SELECT ta+tb FROM t)
交集INTERSECT:
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. INTERSECT
sql中union多表合并3. SELECT ta FROM t;
可以写成
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. WHERE sa IN
3. (SELECT ta FROM t)
当然也可以写成
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. WHEREEXISTS
3. (SELECT*FROM t WHERE t.ta=s.sa)
或者使⽤连接
PLAIN TEXT
SQL:
1. SELECT sa FROM s, t
2. WHERE sa = ta
实际上这⼏个语句都有点问题,就是INTERSECT在出现重复时的语义问题。按照SQL-3标准,类似UNION,可以有明确的 INTERSECT ALL或者INTERSECT DISTINCT语法。⼀般的INTERSECT实现并没有明确这⼀点,⽽且从逻辑上讲意义也不⼤。那么当s或t中出现重复的时,如sa='x'的有2 个,sb='x'的有3个,使⽤上⾯的⼦查询将返回2⾏,使⽤连接将返回6⾏,当然这两个语句都可以加上⼀个DISTINCT,就实现了 INTERSECT DISTINCT语义了。
并集UNION:
MySql从4.0开始就⽀持UNION(ALL 和 DISTINCT)了,为完整起见,也列举⼀下。
其实实现这样⼀个结果是很⿇烦的
PLAIN TEXT
SQL:
1. SELECT sa FROM s
2. UNION DISTINCT
3. SELECT ta FROM t;
需要使⽤外连接,⽽且是Full的外连接
PLAIN TEXT
SQL:
1. SELECTDISTINCT NVL(s.sa, t.ta)
2. FROM s FULL OUTERJOIN t ON(s.sa=t.ta)
上⾯的例⼦中我使⽤了Oracle的语法,实际上MySql不⽀持FULL OUTER JOIN(虽然⽀持LEFT和RIGHT OUTER JOIN),好在MySql⽀持UNION。
对于UNION ALL语义,我还没有想出来⽤普通查询如何实现,如果在上⾯语句中去掉DISTINCT,结果肯定不对。
标签:  ,