【问题标题】:SQL: subquery has too many columnsSQL:子查询的列太多
【发布时间】:2012-09-02 18:29:32
【问题描述】:

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

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    您在子查询中投影 三个 列,但在 IN 子句中比较单个 一个。在子查询中为 IN 选择所需的列 (r1.king):

    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
    );
    

    【讨论】:

    • 另外,如果可以,请尝试将子查询移动到 from 子句中(作为具有合适字段的派生表加入),因为它会更快,只评估一次,而不是每行一次。
    【解决方案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
    ;
    

    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 ... )
    ;
    

    【讨论】:

    • 感谢您指出 ROW 选项!解决了我的(略有不同的)问题:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    相关资源
    最近更新 更多