可以在Postgres中有效地LEFT OUTER JOIN左表行的子集吗?

DNS*_*DNS 4 sql postgresql performance join

假设我有以下表格:

table_1                  table_2
id_a    name             id_a    id_b
1       c                1       1
2       a                1       2
3       b                2       1
                         2       2
Run Code Online (Sandbox Code Playgroud)

现在考虑以下LEFT OUTER JOIN:

SELECT *
FROM table_1
LEFT OUTER JOIN table_2 USING (id_a)

id_a    name  id_b  
1       c     1
1       c     2
2       a     1
2       a     2
3       b
Run Code Online (Sandbox Code Playgroud)

现在假设'FROM table_1'实际上是一个复杂的子查询,如:

SELECT * FROM huge_table WHERE expensive_conditions_producing_three_rows
Run Code Online (Sandbox Code Playgroud)

是否可以编写仅以最小名称连接左侧行的查询,而无需完全重新运行子查询?您可以假设您对子查询有一些控制权,即您可以根据需要添加ORDER BY.

换句话说,最终结果应如下所示:

id_a    name  id_b
1       c
2       a     1
2       a     2
3       b
Run Code Online (Sandbox Code Playgroud)

我考虑使用SELECT INTO将子查询结果放在临时表中.那么计算JOIN ON条件下使用的最小值不会有问题.但我宁愿避免这种情况,除非它是唯一的解决方案.

编辑:我会等待几天,然后接受最佳解决方案,无论PG版本如何.但是,在PG 8.3及更早版本中工作的一个将非常感激.

Erw*_*ter 5

为此使用CTE(通用表表达式) (适用于 PostgreSQL 8.4 或更高版本):

WITH cte AS (
    SELECT id_a, name
    FROM   table_1
    WHERE  expensive_conditions_producing_three_rows
    )
SELECT c.id_a, c.name, t2.id_b
FROM   cte c
LEFT   JOIN table2 t2 ON t2.id_a = c.id_a
                     AND t2.name = (SELECT min(name) FROM cte)
Run Code Online (Sandbox Code Playgroud)

  • 在 SQL Server 中,CTE 更类似于视图而不是临时表。我想,如果您在同一个查询中多次引用一个视图,您可能会准备好接受该视图也可以被多次评估的事实。CTE(在 SQL Server 中)也是如此。优化器*可能*消除一些重新评估,但这远不能得到保证。 (2认同)

ype*_*eᵀᴹ 5

使用Window函数(可从PostgreSQL 8.4获得):

SELECT *
FROM
      ( SELECT *
             , ROW_NUMBER() OVER (ORDER BY SomeColumn) AS RowNum
        FROM table_1
      ) AS a
  LEFT JOIN
      table_2 AS b
    ON 
       (join condition)
    AND
       a.RowNum = 1
Run Code Online (Sandbox Code Playgroud)