29

postgresql でクエリを作成しようとしています。データベースには 2 つの関係が含まれています。イギリスの王を含む "kingdom" と、スチュアート王朝の人々を含む "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 の中にあるものは正しいです。

4

2 に答える 2

33

サブクエリで3 つの列を投影していますが、句でそれらの1 つを比較しています。サブクエリでIN必要な列 ( r1.king)だけを選択します。IN

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
);
于 2012-09-02T18:31:04.550 に答える
13

回答されたように、列数は一致しませんでしたが、これを書くもっと簡単な方法があります。

クエリを作成するときは、段階的に検討することをお勧めします。まず、各王が亡くなったときの年齢を知る必要があります。

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
;

個別の on は個別の値ごとに最初の行を取得するため、正しい とペアにすることが重要ですORDER BY。最初に王朝の名前で並べ、次に王が住んでいた期間が長い順に並べます。つまり、各王朝で最初に表示される王が最も長命の王であり、DISTINCT ON が各王朝で保持する記録です。

kindgom への JOIN も削除しましたが、必要に応じて再度追加できます。

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 ... )
;
于 2015-03-18T01:57:34.827 に答える