我可以编写不带 OR IS NULL 的 FULL OUTER JOIN 吗?

And*_*eKR 3 postgresql join syntax

这里有一些可以使用的数据:

CREATE TABLE a (
    a_id   int  NOT NULL,
    a_prop text NOT NULL
);

CREATE TABLE b (
    b_id   int  NOT NULL,
    b_prop text NOT NULL
);

INSERT INTO a VALUES (1, 'blah'), (2, 'blah'), (4, 'not this one');
INSERT INTO b VALUES (1, 'blah'), (3, 'blah'), (5, 'not this one');
Run Code Online (Sandbox Code Playgroud)

现在我想编写一个返回的查询:

结果

一种可能性是:

SELECT *
FROM a
FULL OUTER JOIN b ON a_id = b_id
WHERE (a_prop = 'blah' OR a_prop IS NULL)
AND (b_prop = 'blah' OR b_prop IS NULL);
Run Code Online (Sandbox Code Playgroud)

OR ... IS NULL这要求我为我有条件的每个字段都写。如果某些条件是日期范围等,这会变得更加冗长。

如果这是左连接:

SELECT *
FROM a
LEFT JOIN b ON a_id = b_id
WHERE a_prop = 'blah'
AND (b_prop = 'blah' OR b_prop IS NULL);
Run Code Online (Sandbox Code Playgroud)

我可以将条件移至ON子句中以避免这种情况:

SELECT *
FROM a
LEFT JOIN b ON a_id = b_id AND b_prop = 'blah'
WHERE a_prop = 'blah';
Run Code Online (Sandbox Code Playgroud)

有没有办法通过完整的外连接来做到这一点?

小提琴

Erw*_*ter 5

没有OR IS NULL

col = 'x' OR col IS NULL

原来的:

SELECT *
FROM   a
FULL   JOIN b ON a_id = b_id
WHERE (a_prop = 'blah' OR a_prop IS NULL)
AND   (b_prop = 'blah' OR b_prop IS NULL);
Run Code Online (Sandbox Code Playgroud)

使用col <> x IS NOT TRUE

SELECT *
FROM   a
FULL   JOIN b ON a_id = b_id
WHERE  a_prop <> 'blah' IS NOT TRUE
AND    b_prop <> 'blah' IS NOT TRUE;
Run Code Online (Sandbox Code Playgroud)

或者在加入之前过滤:

SELECT *
FROM      (SELECT * FROM a WHERE a_prop = 'blah') a
FULL JOIN (SELECT * FROM b WHERE b_prop = 'blah') b ON a_id = b_id;
Run Code Online (Sandbox Code Playgroud)

col <> 'x' OR col IS NULL

问题的第一个版本要求这个谓词。

原来的:

SELECT *
FROM a
FULL OUTER JOIN b ON a_id = b_id
WHERE (a_prop <> 'not this one' OR a_prop IS NULL)
AND   (b_prop <> 'not this one' OR b_prop IS NULL);
Run Code Online (Sandbox Code Playgroud)

使用col IS DISTINCT FROM 'x'

SELECT *
FROM   a
FULL   JOIN b ON a_id = b_id
WHERE  a_prop IS DISTINCT FROM 'not this one'
AND    b_prop IS DISTINCT FROM 'not this one';
Run Code Online (Sandbox Code Playgroud)

或者在加入之前过滤:

SELECT *
FROM      (SELECT * FROM a WHERE a_prop <> 'not this one') a
FULL JOIN (SELECT * FROM b WHERE b_prop <> 'not this one') b ON a_id = b_id;
Run Code Online (Sandbox Code Playgroud)

db<>fiddle这里- 显示所有

!=旁白:我没有使用<>,它是 SQL 中的标准运算符。(!=是 Postgres 中可接受的别名。)