2012-02-02 13 views
4

比方說,我有如下表:能否有效地在LEGO OUTER上加入Postgres中左錶行的子集?

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 

現在考慮下面的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 

現在想象一下 'FROM TABLE_1' 實際上是一個複雜的子查詢,如:

SELECT * FROM huge_table WHERE expensive_conditions_producing_three_rows 

是否可以編寫一個查詢,只使用最小名稱與左行進行連接,而無需完全重新運行子查詢?您可以假定您對子查詢有一定的控制權,即可以根據需要添加ORDER BY。

換句話說,最終的結果應該是這樣的:

id_a name id_b 
1  c 
2  a  1 
2  a  2 
3  b 

我認爲使用SELECT INTO放置在一個臨時表的子查詢結果。那麼計算JOIN ON條件下使用的最小值就不成問題。但我寧願避免這種情況,除非它是唯一的解決方案。

編輯:我會等幾天,然後接受最好的解決方案,無論PG版本如何。但是,在PG 8.3和更早的版本中工作的人將會非常感激。

+0

試圖使用這些HTTP:// WWW。 postgresql.org/docs/8.4/static/queries-with.html? – 2012-02-02 22:15:05

+0

哪個Postgres版本? – 2012-02-02 23:30:32

+0

我沒有指定一個版本,因爲我想保持這個問題對其他人做類似的事情有用。但我個人很喜歡看到在PG 8.3中有效的東西。 – DNS 2012-02-03 02:02:11

回答

3

使用一個CTE (common table expression)(僅適用於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) 
+0

不知道PostgreSQL,但在SQL Server中,這可能會導致*'不全部重新運行子查詢*'部分的問題,因爲'cte'會被評估兩次。 – 2012-02-03 11:18:33

+0

@AndriyM:在PostgreSQL中它肯定沒有。 (經過測試驗證,但那是浪費我的時間。)CTE的**整點**是在不重新運行查詢的情況下使用結果值。現在,我不知道SQL服務器,但我堅信,做相反的事情是愚蠢的。 – 2012-02-03 16:42:54

+2

在SQL Server中,CTE比臨時表更類似於視圖。我想,如果你在同一個查詢中多次引用一個視圖,那麼你可能已經準備好了可以多次評估該視圖的事實。所以這是CTE(在SQL Server中)。優化器*可能會消除一些重新評估,但遠未得到保證。 – 2012-02-03 18:23:09

5

使用Window functions(可從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