SQL: подзапрос имеет слишком много столбцов

Я пытаюсь сделать запрос с помощью postgresql. База данных содержит два отношения:" Королевство", в которое входят некоторые английские короли, и" династия", в которой содержатся некоторые люди из династии Стюарта

отношение "королевство" включает в себя имя короля и когда его королевство началось и закончилось. Отношение "династия" включает в себя имя, пол, рождение и смерть.

С моим запросом я получение этой ошибки в строке 3 (не в):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
);

то, что находится внутри не в правильно.

2 ответов


вы проецируете три столбцы в вашем подзапросе, но сравнение одного один их в 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
);

как было сказано, количество столбцов не совпадало, но есть гораздо более простой способ написать это.

при написании запросов лучше всего продумывать их поэтапно. Во-первых, вам нужно знать, сколько лет было каждому королю, когда они умерли:

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
;

distinct on будет принимать первую строку для каждого отдельного значения, поэтому важно, чтобы вы связали его с правильный ORDER BY. Сначала мы заказываем по имени династии, затем, как долго жил король в порядке убывания. Это означает, что первый король, показанный для каждой династии, будет самым долгоживущим, и это запись, которая будет сохраняться для каждой династии.

обратите внимание, что я также удалил соединение с 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 () construct:

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