不久前(大约 2004 年),我在一个团队中担任后端开发人员,每个人都使用 where 子句加入。作为使用内/外连接的支持者,我向他们展示了一个 where 子句连接的示例,该示例说明了它如何根据数据产生不明确的结果,以及外连接如何避免该问题。
我必须做同样的演示,但再也找不到那个片段了。它在我的文件档案中的某个地方,不幸的是我无权访问。有没有人有一个方便的例子?
这只能在设置为 80 兼容级别(或 SQL Server <= 2000)的数据库上证明。
CREATE TABLE dbo.splunge(splunge_id INT);
CREATE TABLE dbo.mort(splunge_id INT, name VARCHAR(32));
INSERT dbo.splunge(splunge_id) SELECT 1 UNION SELECT 2 UNION SELECT 3;
INSERT dbo.mort(splunge_id, name) SELECT 1,'hi' UNION SELECT 2,NULL;
-- returns all three rows - should it?
SELECT *
FROM dbo.splunge AS s, dbo.mort AS m
WHERE s.splunge_id *= m.splunge_id
AND m.name IS NULL;
-- returns rows 2 and 3
SELECT *
FROM dbo.splunge AS s
LEFT OUTER JOIN dbo.mort AS m
ON s.splunge_id = m.splunge_id
WHERE m.name IS NULL;
DROP TABLE dbo.splunge, dbo.mort;
Run Code Online (Sandbox Code Playgroud)
不想使用可为空的名称列来演示?好的,一个可为空的外键列怎么样?
CREATE TABLE dbo.splunge(splunge_id INT);
CREATE TABLE dbo.mort(splunge_id INT);
INSERT dbo.splunge(splunge_id) SELECT 1 UNION SELECT 2 UNION SELECT 3;
INSERT dbo.mort(splunge_id) SELECT 1 UNION SELECT 2 UNION SELECT NULL;
-- returns all three rows - should it?
SELECT *
FROM dbo.splunge AS s, dbo.mort AS m
WHERE s.splunge_id *= m.splunge_id
AND m.splunge_id IS NULL;
-- only returns row 3 (because it was the only row truly missing)
SELECT *
FROM dbo.splunge AS s
LEFT OUTER JOIN dbo.mort AS m
ON s.splunge_id = m.splunge_id
WHERE m.splunge_id IS NULL;
DROP TABLE dbo.splunge, dbo.mort;
Run Code Online (Sandbox Code Playgroud)
不知道为什么你今天需要证明这一点 - 你根本不应该使用*= / =*
连接,无论你是否可以重现一些模棱两可的行为 - 它们已被弃用并且在任何不支持 80 兼容性的数据库中都不起作用等级。如果您使用的是 80 级兼容性,则在最终升级时,您需要为大量其他功能差异和潜在的破坏性更改做好准备。