2012-09-02 97 views
14

我想用postgresql進行查詢。 該數據庫包含兩個關係:「王國」,其中包括一些英國國王,和「dinasty」,其中包含一些來自斯圖爾特王朝的人SQL:子查詢有太多列

關係「王國」包括國王的名字,當他的王國開始和結束。關係「dinasty」包括姓名,性別,出生和死亡。

我想要查詢的是當他去世時最老的國王。

隨着我的查詢我在LINE 3(NOT IN)收到此錯誤:subquery has too many columns

這是查詢:

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king, R1.birth, R1.death 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 

裏面是什麼的NOT IN是正確的。

+1

它不會影響您的代碼,但請正確拼寫王朝。 –

回答

18

你伸出你的子查詢列,但IN子句中比較它們的單一個。只選擇在子查詢IN所需的列(r1.king):

SELECT kingdom.king, dinasty.birth, dinasty.death 
FROM kingdom, dinasty 
WHERE kingdom.king = dinasty.name AND kingdom.king NOT IN 
(
    SELECT DISTINCT R1.king 
    FROM 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R1, 
    (
     SELECT DISTINCT R1.king, D1.birth, D1.death 
     FROM kingdom AS R1, dinasty AS D1, dinasty AS D2 
     WHERE R1.king=D1.name 
    ) AS R2 
    WHERE R1.death-R1.birth < R2.death-R2.birth 
); 
+0

非常感謝:) – Epi

+0

此外,如果可以這樣做,請嘗試將子查詢移動到from子句中(作爲具有合適字段的派生表來加入),因爲它將快得多,僅評估一次,而不是每行一次。 – d11wtq

8

正如有人接聽,您的列數不匹配,但有一個更簡單寫這種方式。

在編寫查詢時,最好分階段思考。首先,你需要知道每個國王多大年紀時,他們死了:

SELECT *, death-birth AS lived_for FROM dinasty 

現在,你有,你可以使用DISTINCT ON找到每個王國

SELECT DISTINCT ON(name) name, birth, death, lived_for 
    FROM (
     SELECT *, death-birth AS lived_for FROM dinasty 
    ) a 
    ORDER BY name, lived_for DESC 
; 

最長壽的國王不同的值將會爲每個不同的值取第一行,所以將其與正確的ORDER BY配對非常重要。首先我們按照dinasty的名字命令,然後國王爲降序多久。這意味着每一場比賽的第一位國王將是最長的國王,這是DISTINCT ON將爲每場比賽保留的紀錄。

請注意,我也去掉了JOIN來kindgom,但你可以添加如果需要的話,早:

SELECT k.*, oldest.* 
    FROM (
    SELECT DISTINCT ON(name) name, birth, death, lived_for 
     FROM (
      SELECT *, death-birth AS lived_for FROM dinasty 
     ) a 
     ORDER BY name, lived_for DESC 
    ) oldest 
    JOIN kingdom k ON k.king = oldest.name 
; 

最後,如果你需要使用多個列的子選擇,你可以使用ROW()構造:

SELECT ... 
    FROM table_a 
    WHERE ROW(f1, f2, f3) NOT IN (SELECT f1a, f2a, f3a FROM ...) 
; 
+0

爲什麼這是低調? –

+0

好問題;對我來說沒有什麼明顯的錯誤 - 留下一個解釋性的評論會是有禮貌的。 –

+0

感謝您指出行選項!解決了我(稍有不同)的問題:) – wmebane