SQL:子查询有太多列

时间:2012-09-02 18:29:32

标签: sql postgresql

我正在尝试使用postgresql进行查询。 该数据库包含两个关系:“王国”,其中包括一些英国国王,以及“dinasty”,其中包含一些来自斯图尔特晚宴的人

关系“王国”包括国王的名字,当他的王国开始和结束时。 “dinasty”的关系包括姓名,性别,出生和死亡。

我想要查询的是他去世时最年长的国王。

根据我的查询,我在第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
);

NOT IN内部的内容是正确的。

2 个答案:

答案 0 :(得分:23)

您正在子查询中投射三个列,但在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
);

答案 1 :(得分:9)

如上所述,您的列数并不匹配,但是编写此列的方式要简单得多。

在撰写查询时,最好分阶段进行思考。首先,你需要知道每个国王死后的年龄:

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配对非常重要。首先,我们按照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 ... )
;