SQL: в подзапросе слишком много столбцов
Я пытаюсь сделать запрос с postgresql.
База данных содержит два отношения: "царство", в которое входят некоторые английские короли, и "династия", в которой содержатся некоторые люди из дикой природы Стюарта
Отношение "царство" включает в себя имя короля и когда его царство начиналось и заканчивалось. Отношение "династия" включает имя, пол, рождение и смерть.
То, что я пытаюсь запросить, это король, который был самым старым, когда он умер.
По моему запросу я получаю эту ошибку в 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
Вы проецируете три столбца в свой подзапрос, но сравниваете один из них в предложении 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
);
Ответ 2
Как уже было сказано, количество столбцов не совпало, но есть гораздо более простой способ написать это.
При написании запросов лучше всего их проработать поэтапно. Во-первых, вам нужно знать, сколько лет каждому королю было, когда они умерли:
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
. Сначала мы заказываем имя династии, а затем, как долго царь жил в порядке убывания. Это означает, что первый король, показанный для каждой династии, будет самым долгоживущим, и это будет запись, которую 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 ... )
;