【问题标题】:Multiple conditions in INNER JOIN [duplicate]INNER JOIN 中的多个条件 [重复]
【发布时间】:2019-06-04 16:59:14
【问题描述】:

我有两个表 userproduct 具有一对多关系(一个 user 可能有多个 products)。

我想创建一个查询来获取所有既有橙子又有香蕉的users。在下面的示例中,这将是 johnleeroy

如何制定我的查询来做到这一点?

只有一个条件我会去:

SELECT * FROM "user" 
INNER JOIN "product" ON "product"."fk_user" = "user"."id"
WHERE "product"."product" = 'banana';

user

╔════╦═════════╗
║ id ║ name    ║
╠════╬═════════╣
║ 1  ║ michael ║
╠════╬═════════╣
║ 2  ║ john    ║
╠════╬═════════╣
║ 3  ║ leeroy  ║
╠════╬═════════╣
║ 4  ║ tony    ║
╚════╩═════════╝

product

╔═════════╦═════════╗
║ product ║ fk_user ║
╠═════════╬═════════╣
║ orange  ║ 1       ║
╠═════════╬═════════╣
║ orange  ║ 2       ║
╠═════════╬═════════╣
║ banana  ║ 2       ║
╠═════════╬═════════╣
║ banana  ║ 3       ║
╠═════════╬═════════╣
║ orange  ║ 3       ║
╠═════════╬═════════╣
║ banana  ║ 4       ║
╚═════════╩═════════╝

【问题讨论】:

  • 一个连接可能还不够。
  • 您不需要加入。请参阅我对此的回答。顺便说一下,这不是产品表。因为表中的记录不能唯一地代表一个产品。理想情况下,您应该有一个每个产品一行的产品表和一个链接产品和用户的 user_product 表。
  • 您是否只需要user_iduser 表中的更多列?是否有 FOREIGN KEY 约束来强制引用完整性?一个UNIQUE 约束禁止product(product, fk_user) 上的欺骗?您的 Postgres 版本?

标签: sql postgresql relational-division


【解决方案1】:

您可以使用两个连接:

SELECT u.* 
FROM user u
INNER JOIN product p1
ON p1.fk_user=u.id
AND p1.product='banana'
INNER JOIN product p2
ON p2.fk_user=u.id
AND p2.product='orange'

【讨论】:

  • 我猜一个香蕉应该是橙子。 ;)
  • @stickybit derp duh derp derp。谢谢
【解决方案2】:

按用户分组并使用HAVING查看用户的产品。

select *
from user
where id in
(
  select fk_user
  from product
  group by fk_user
  having count(case when product = 'orange' then 1 end) > 0
     and count(case when product = 'banana' then 1 end) > 0
);

编辑:我应该补充一点,有几种方法可以编写这样的子查询。 WHERE 子句可以加快速度,并且使用这样的子句,您可以只计算找到的不同产品:

select *
from user
where id in
(
  select fk_user 
  from product 
  where product in ('orange', 'banana') 
  group by fk_user
  having count(distinct product) = 2 -- two different products: orange and banana
);

【讨论】:

    【解决方案3】:

    最直接的声明(恕我直言)是使用两个IN 子句:

    select *
    from user
    where id in
    (
      select fk_user
      from product
      WHERE product = 'orange')
    and id in
    (
      select fk_user
      from product
      WHERE product = 'banana')
    

    【讨论】:

    • Canonical 可能不是正确的词——我的意图是说“最直接的声明式”方式。这是表达查询 intent 的最接近的 SQL(EXISTS 是紧随其后的第二个恕我直言)
    • 很公平。 (EXISTS 将从我的立场赢得这场竞争 - 它可以更快,但永远不会更慢。)
    【解决方案4】:

    如果您只需要用户 ID 而不是名称,则可以使用聚合:

    SELECT p.fk_user
    FROM product p
    WHERE p.product in ('banana', 'orange')
    GROUP BY p.fk_user
    HAVING COUNT(*) FILTER (WHERE p.product = 'banana') > 0 AND
           COUNT(*) FILTER (WHERE p.product = 'orange') > 0;
    

    如果您还需要来自 user 的其他列,我会使用 DStanley 建议的 IN 版本,尽管我会使用 EXISTS 而不是 IN

    【讨论】:

      【解决方案5】:

      这是的案例。
      如果(就像是典型案例,您的示例数据似乎支持它)...

      • 您只需要用户 ID
      • 有一个 FOREIGN KEY 约束强制引用完整性
      • product(product, fk_user) 上的UNIQUE 约束-(对于我的查询,隐式providing the perfect index

      ..那么这是最快的:

      SELECT fk_user
      FROM   product b
      JOIN   product o USING (fk_user)
      WHERE  b.product = 'banana'
      AND    o.product = 'orange';
      

      我们在这里收集了一系列基本技术:

      最佳选择取决于缺少的规格 - 以及一定程度上的个人偏好。

      顺便说一句:user 是保留字,请勿将其用作表名。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 2011-05-29
        • 1970-01-01
        • 2012-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多