fragments

Apr 26, 2019

MySQL中的并、差、交和除运算

Last updated at: Apr 26, 2019

翻译自Union, Difference, Intersection, and Division in MySQL

构建数据库

-- 创建a和b表
CREATE TABLE a (x INT, y VARCHAR(5));
CREATE TABLE b (x INT, y VARCHAR(5));
-- 插入数据到a表
INSERT INTO a(x,y) VALUES(1,'A');
INSERT INTO a(x,y) VALUES(2,'B');
INSERT INTO a(x,y) VALUES(3,'C');
INSERT INTO a(x,y) VALUES(4,'D');
-- 插入数据到b表
INSERT INTO b(x,y) VALUES(1,'A');
INSERT INTO b(x,y) VALUES(3,'C');

SELECT * FROM a;
+------+------+
| x    | y    |
+------+------+
|    1 | A    |
|    2 | B    |
|    3 | C    |
|    4 | D    |
+------+------+

SELECT * FROM b;
+------+------+
| x    | y    |
+------+------+
|    1 | A    |
|    3 | C    |
+------+------+

并集(Union)

SELECT * FROM a UNION SELECT * FROM b;
+------+------+
| x | y |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
+------+------+

SELECT * FROM a UNION ALL SELECT * FROM b;
+------+------+
| x | y |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 1 | A |
| 3 | C |
+------+------+

差集(Difference)

SELECT * FROM a WHERE (x,y) NOT IN (SELECT * FROM b);
+------+------+
| x | y |
+------+------+
| 2 | B |
| 4 | D |
+------+------+

SELECT * FROM a
WHERE NOT EXISTS (SELECT * FROM b WHERE b.x = a.x AND b.y = a.y);
+------+------+
| x | y |
+------+------+
| 2 | B |
| 4 | D |
+------+------+

-- 最高效的方式
SELECT DISTINCT a.x AS x, a.y AS y
FROM a LEFT OUTER JOIN b USING (x, y) WHERE b.x IS NULL;
+------+------+
| x | y |
+------+------+
| 2 | B |
| 4 | D |
+------+------+

交集(Intersection)

SELECT * FROM a WHERE (x,y) IN (SELECT * FROM b)
+------+------+
| x | y |
+------+------+
| 1 | A |
| 3 | C |
+------+------+

SELECT * FROM a
WHERE EXISTS (SELECT * FROM b WHERE b.x=a.x AND b.y = a.y);
+------+------+
| x | y |
+------+------+
| 1 | A |
| 3 | C |
+------+------+

-- 最高效的方式
SELECT DISTINCT a.x AS x, a.y AS y
FROM a INNER JOIN b USING (x,y);
+------+------+
| x | y |
+------+------+
| 1 | A |
| 3 | C |
+------+------+

构建数据库

-- 创建c和d表
CREATE TABLE c (x INT, y VARCHAR(5));
CREATE TABLE d (x INT);
-- 插入数据到c表
INSERT INTO c(x,y) VALUES(1,'A');
INSERT INTO c(x,y) VALUES(2,'A');
INSERT INTO c(x,y) VALUES(3,'A');
INSERT INTO c(x,y) VALUES(1,'B');
INSERT INTO c(x,y) VALUES(2,'B');
INSERT INTO c(x,y) VALUES(3,'C');
INSERT INTO c(x,y) VALUES(3,'D');
-- 插入数据到d表
INSERT INTO d(x) VALUES(1);
INSERT INTO d(x) VALUES(2);
INSERT INTO d(x) VALUES(3);

除法(Division)

SELECT DISTINCT c1.y AS y
FROM c c1
WHERE NOT EXISTS
 (SELECT d.x FROM d
 WHERE d.x NOT IN (SELECT c2.x FROM c c2 WHERE c2.y = c1.y));
+------+
| y |
+------+
| A |
+------+

SELECT DISTINCT c1.y AS y
FROM c c1
WHERE NOT EXISTS
 (SELECT * FROM d
 WHERE NOT EXISTS (SELECT * FROM c c2 WHERE c2.y = c1.y AND c2.x = d.x));
+------+
| y |
+------+
| A |
+------+

不起作用的SQL:

-- does not work;
SELECT DISTINCT c1.y AS y
FROM c c1
WHERE NOT EXISTS
 (SELECT d.x FROM d LEFT OUTER JOIN c c2 USING (x)
 WHERE c2.y = c1.y AND c2.x IS NULL );
+------+
| y |
+------+
| A |
| B |
| C |
| D |
+------+
-- does not work;
SELECT DISTINCT c1.y AS y
FROM c c1
WHERE NOT EXISTS
 (SELECT * FROM d LEFT OUTER JOIN c c2
 ON (d.x = c2.x) WHERE c2.y = c1.y AND c2.x IS NULL );
+------+
| y |
+------+
| A |
| B |
| C |
| D |
+------+
-- does not work;
SELECT DISTINCT c1.y AS y
FROM c c1
WHERE NOT EXISTS
 (SELECT * FROM d LEFT OUTER JOIN c c2
 ON (d.x = c2.x AND c2.y = c1.y AND c2.x IS NULL) );
ERROR 1054 (42S22): Unknown column 'c1.y' in 'on clause'

参考

(694 words)