一般情况下的回答:
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
详细解答:
问:字母 SQL 代表什么?A. 几乎没有资格作为一门语言...... ROFL 但请考虑以下严重问题:
CREATE TABLE MyTable
( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );
DECLARE @MyTable TABLE
( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );
现在提问:
问:在语言(计算机科学)术语中,是@MyTable
一个变量吗?一口井...
问题 1:无法将表值分配给@MyTable
eg
-- Assignment attempt 1:
SET @MyTable = MyTable; -- COMPILE ERROR
-- Assignment attempt 2:
SET @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) ); -- COMPILE ERROR
问题 2:无法比较变量,例如
-- Comparison attempt 1:
IF ( @MyTable = @MyTable ) BEGIN;
PRINT 'Tables are the same.'
END; -- COMPILE ERROR
-- Comparison 2:
IF ( @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) ) ) BEGIN;
PRINT 'Tables are the same.'
END; -- COMPILE ERROR
...所以我们必须相信 @MyTable 是一个既不支持赋值也不支持比较的“变量”。
问:如果@MyTable
是一个变量,在语言(计算机科学)术语中是MyTable
什么?A. 常数?价值?类型?班级?结构?以上都不是?
...是的,SQL 确实是一种非常奇怪的语言!
问:什么是关系运算符?A. 在关系模型中,它是一个以两个关系值作为参数并返回一个关系值作为结果的运算符。
问:SQL 是否支持关系运算符?答:不完全是。SQL 确实具有真正关系语言的用户所熟悉的运算符(UNION
、INTERSECT
、EXCEPT
等)。但是,SQL 支持非关系特性,最显着的是空值、重复行和重复列名。因此,需要非常小心地确保这些运算符的参数和结果等价于关系。
Q 如何使用 SQL 的“关系式”运算符比较两个表的相等性?A 这是一种方法:
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
测试以证明上述内容(注意以下并非所有关系值,但确实证明了运算符在 SQL 空值上的逻辑工作):
示例 1:表相同(期望零行 == PASS):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
示例 2:tableB 是 tableB 的真子集(期望行 == FAIL):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
示例 3:tableA 是 tableB 的真子集(期望行 == FAIL):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 3, 'Test' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 2, '' ),
( 3, 'Test' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
示例 4:tableA 和 tableB 有一些但不是所有的共同行值(期望行 == FAIL):
WITH tableA AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 4, 'Lone' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 1, NULL ),
( 4, 'Sole' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
示例 5:tableA 和 tableB 没有共同的行值(期望行 == FAIL):
WITH tableA AS
( SELECT * FROM ( VALUES ( 5, NULL ),
( 6, 'Different' )
) AS T ( ID, data_col ) ),
tableB AS
( SELECT * FROM ( VALUES ( 7, NULL ),
( 8, 'Not the same' )
) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA
INTERSECT
SELECT * FROM tableB;
问:为什么 SQL Server DBA 倾向于不使用这种语法,而更喜欢使用FULL OUTER JOIN
. A. 可能出于多种原因,例如熟悉遗留语法(例如EXCEPT
在 SQL Server 2005 中引入)。但最有可能的是,SQL DBA 倾向于编写他们认为最有效的查询(贬义,过早优化)。确实,SQL Server 优化器不能很好地处理运算符INTERSECT
和EXCEPT
.
问:为什么更喜欢“关系型”运算符?A. 因为它们不那么冗长并且可以说更容易阅读。这两个都是测试代码的好品质。