如何仅从 PostgreSQL 的内部联接中不存在 id 的表中选择行?
Posted
技术标签:
【中文标题】如何仅从 PostgreSQL 的内部联接中不存在 id 的表中选择行?【英文标题】:How can I select only the rows from a table with ids that don't exist in an inner join in PostgreSQL? 【发布时间】:2020-01-28 18:20:20 【问题描述】:我有下表
postgres=# select * from joins_example;
user_id | price | id | email
---------+--------+----+--------------------------
1 | $30.00 | |
5 | $50.00 | |
7 | $20.00 | |
| | 1 | hadil@example.com
| | 5 | saiid@example.com
| | 2 | fahir@example.com
6 | $60.00 | 6 | oma@example.com
8 | $40.00 | 8 | nasim@example.com
| | 8 | nasim.hassan@example.com
9 | $40.00 | 9 | farah@example.com
9 | $70.00 | |
10 | $80.00 | | majid@example.com
| | 10 | majid.seif@example.com
(13 rows)
user_id
和 id
之间的自内连接产生
postgres=# select * from joins_example as x inner join joins_example as y on x.user_id = y.id;
user_id | price | id | email | user_id | price | id | email
---------+--------+----+-------------------+---------+--------+----+--------------------------
1 | $30.00 | | | | | 1 | hadil@example.com
5 | $50.00 | | | | | 5 | saiid@example.com
6 | $60.00 | 6 | oma@example.com | 6 | $60.00 | 6 | oma@example.com
8 | $40.00 | 8 | nasim@example.com | | | 8 | nasim.hassan@example.com
8 | $40.00 | 8 | nasim@example.com | 8 | $40.00 | 8 | nasim@example.com
9 | $40.00 | 9 | farah@example.com | 9 | $40.00 | 9 | farah@example.com
9 | $70.00 | | | 9 | $40.00 | 9 | farah@example.com
10 | $80.00 | | majid@example.com | | | 10 | majid.seif@example.com
(8 rows)
我想要的是:
user_id | price | id | email | user_id | price | id | email
---------+--------+----+-------------------+---------+--------+----+--------------------------
7 | $50.00 | | | | | |
| | | | | | 2 | fahir@example.com
或:
user_id | price | id | email | user_id | price | id | email
---------+--------+----+-------------------+---------+--------+----+--------------------------
| | | | 7 | $50.00 | |
| | 2 | fahir@example.com | | | |
偶数
user_id | price | id | email
---------+--------+----+--------------------------
5 | $50.00 | |
| | 2 | fahir@example.com
会是一个好的开始。
具体来说,我想知道如何仅从joins_example
和user_id
s 或id
s 中选择内部联接中不存在的行。
【问题讨论】:
是否可以安全地假设user_id
和 id
在一行中相等,如果两者都设置了?为什么你想要上面两个输出之一而不是最后一个?没有额外的信息,你只需要更多的检查来确定你的值在哪里
附加信息是如果它是作为连接的一部分生成的,它将来自交叉积的哪一侧。这超出了问题的范围,但我希望将它与内部连接结合起来。完全连接包含内部连接以及两边都为空的交叉行。这对于引用不同表的联接是可以的,但对于自联接,它会创建许多包含与匹配搜索条件的行相同的信息的行。我想要一种快速、直观且无损的方法来对高度异构的数据进行自我连接。
您也可以在最后的输出中找到“侧面”信息。您只需要查找 2 个连接字段中的哪一个为空
啊,我明白了。现在我只需要用union
able 的格式对这些信息进行编码,并使用内部连接。
我现在看到你是对的,没有额外的信息,因为在交叉产品中两者都会出现在两边。这意味着其余列可以简单地为空。
【参考方案1】:
您可以考虑使用具有NOT EXISTS
条件的相关子查询的方法:
select *
from joins_example as x
where
(
x.user_id is not null
and not exists (
select 1 from joins_example y where x.user_id = y.id
)
)
or (
x.id is not null
and not exists (
select 1 from joins_example y where x.id = y.user_id
)
)
Demo on DB Fiddle:
| user_id | price | id | email |
| ------- | ----- | --- | ----------------- |
| 7 | 20.00 | | |
| | | 2 | fahir@example.com |
【讨论】:
【参考方案2】:SELECT *
FROM joins_example j
WHERE (j.user_id IS NULL AND j.id IS NULL)
OR (j.user_id IS NOT NULL AND NOT EXISTS(SELECT 1 FROM joins_example j2 WHERE j2.id = j.user_id))
OR (j.id IS NOT NULL AND NOT EXISTS(SELECT 1 FROM joins_example j2 WHERE j2.user_id = j.id));
【讨论】:
【参考方案3】:SELECT *
FROM joins_example AS w
LEFT JOIN (
select x.user_id
from joins_example as x
inner join joins_example as y on x.user_id = y.id
) AS z ON z.user_id = w.user_id or z.user_id = w.id
WHERE z.user_id IS NULL;
是一个足够好的开始,即
user_id | price | id | email | user_id
---------+--------+----+-------------------+---------
7 | $20.00 | | |
| | 2 | fahir@example.com |
【讨论】:
以上是关于如何仅从 PostgreSQL 的内部联接中不存在 id 的表中选择行?的主要内容,如果未能解决你的问题,请参考以下文章
HIVE:如何仅从两个表中的两列中选择第三个表中不存在的不同值?