【问题标题】:Simplifying code with nested JOINs in WHERE clause在 WHERE 子句中使用嵌套 JOIN 简化代码
【发布时间】:2019-04-26 09:59:35
【问题描述】:

我正在 PostgreSQL 中编写一个 SQL 语句,我在其中加入来自不同表的数据,这些表中的每个表都通过其 id 上的外键连接。表 b 有一个字段 a_id 与表 a 的 id 等相关。

我的问题是我想在 WHERE 子句中重用连接表中的值,而不必再次执行所有 JOIN,如下所示:

SELECT *
FROM a
INNER JOIN b ON b.a_id = a.id
INNER JOIN c ON c.b_id = b.id
WHERE a.id = 3
AND a.x =
    (SELECT c.y
    FROM a
    INNER JOIN b ON b.a_id = a.id
    INNER JOIN c ON c.b_id = b.id
    WHERE a.id = 3
    AND c.id = 5)

我敢打赌,这个 sn-p 有一个更简单的解决方案,我只是没有意识到。如果有人可以帮助我,我会很高兴。

【问题讨论】:

标签: sql postgresql join


【解决方案1】:

我没有可以简化您查询的灵丹妙药,但 CTE 肯定会让您的查询更轻松:

WITH cte AS (
    SELECT *
    FROM a
    INNER JOIN b ON b.a_id = a.id
    INNER JOIN c ON c.b_id = b.id
    WHERE a.id = 3
)

SELECT *
FROM cte
WHERE x IN (SELECT y FROM cte WHERE c_id = 5);

我的别名或列名可能已关闭,您可能需要稍微整理一下 CTE,然后它才能真正为您工作。

【讨论】:

  • 我会使用 IN 而不是 = 子查询,以防万一。
  • @jarlh 是的,我也看到了,但相信 OP 确信它不会发生。
  • 谢谢,这正是我要找的那种结构!
【解决方案2】:

您可以为此使用窗口函数:

SELECT . . .
FROM (SELECT a.*, b.*, c.*,  -- should  list the columns explicitly
             MAX(c.y) FILTER (WHERE c.id = 5) OVER () as y_5
      FROM a INNER JOIN
           b
           ON b.a_id = a.id INNER JOIN
           c
           ON c.b_id = b.id
      WHERE a.id = 3
    ) abc
WHERE abc.x = abc.y_5;

【讨论】:

    【解决方案3】:

    希望下面的查询对您有所帮助。

    SELECT *
    FROM a
    INNER JOIN b ON b.a_id = a.id
    INNER JOIN c ON c.b_id = b.id
    WHERE a.id = 3 and c.id =5 and a.x = c.y
    

    【讨论】:

    • 我的直觉是您的查询与 OP 使用的逻辑不同。考虑c.id <> 5 的记录,如果它恰好与c.y 匹配,它仍可能最终出现在结果集中。
    • 证明它。因为在 where 子句中我使用了 'and' 条件而不是 'or'。
    • Prove it ... 实际上,由 来证明查询使用示例数据有效,这使得 OP 没有提供任何数据。如果你是对的,你很快就会发现,因为 OP 会测试你的代码。
    • 是的,因为我不同意你的观点,因为我申请了 c.id 5 的记录如果恰好匹配 c.y 仍可能最终出现在结果集中条件为 'and' 所以如果 c.id 5 那么 c.y 将不在结果集中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    相关资源
    最近更新 更多