29

我正在尝试使用 postgresql 进行查询。该数据库包含两个关系:“kingdom”,其中包括一些英国国王,以及“dinasty”,其中包含一些来自 stuart 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 里面的内容是正确的。

4

2 回答 2

33

您在子查询中投影列,但在子句中比较其中的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
;

distinct on 将占据每个不同值的第一行,因此将其与正确的 . 配对很重要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 ... )
;
于 2015-03-18T01:57:34.827 回答