【问题标题】:How can I select only the rows from a table with ids that don't exist in an inner join in PostgreSQL?如何仅从 PostgreSQL 的内部联接中不存在 id 的表中选择行?
【发布时间】: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_idid 之间的自内连接产生

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_exampleuser_ids 或ids 中选择内部联接中不存在的行。

【问题讨论】:

  • 是否可以安全地假设 user_idid 在一行中相等,如果两者都设置了?为什么你想要上面两个输出之一而不是最后一个?没有额外的信息,你只需要更多的检查来确定你的值在哪里
  • 附加信息是如果它是作为连接的一部分生成的,它将来自交叉积的哪一侧。这超出了问题的范围,但我希望将它与内部连接结合起来。完全连接包含内部连接以及两边都为空的交叉行。这对于引用不同表的联接是可以的,但对于自联接,它会创建许多包含与匹配搜索条件的行相同的信息的行。我想要一种快速、直观且无损的方法来对高度异构的数据进行自我连接。
  • 您也可以在最后的输出中找到“侧面”信息。您只需要查找 2 个连接字段中的哪一个为空
  • 啊,我明白了。现在我只需要用unionable 的格式对这些信息进行编码,并使用内部连接。
  • 我现在看到你是对的,没有额外的信息,因为在交叉产品中两者都会出现在两边。这意味着其余列可以简单地为空。

标签: sql postgresql inner-join


【解决方案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 |
      

      【讨论】:

        猜你喜欢
        • 2017-07-01
        • 2012-09-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        相关资源
        最近更新 更多