【问题标题】:MySQL Duplicate column error only when query wrapped as subquery仅当查询包装为子查询时,MySQL 重复列错误
【发布时间】:2013-10-30 11:59:43
【问题描述】:

我有一个如下的选择查询:

SELECT * FROM A
LEFT JOIN B ON B.x = A.y
LEFT JOIN C ...
WHERE ....
GROUP BY ...
ORDER BY ...;

所有表都有id 列并且查询运行良好。结果有许多 id 列没有错误,驱动程序处理模棱两可的问题。但我需要对结果有限制,所以我用另一个选择查询包装它,如下所示:

SELECT * FROM (
    SELECT * FROM A
    LEFT JOIN B ON B.x = A.y
    LEFT JOIN C ...
    WHERE ....
    GROUP BY ...
    ORDER BY ...
) AS x WHERE 1 LIMIT 1000;

现在我得到Duplicate column name 'id' 错误!

PS:完整的查询很复杂,我需要使用*(不能列出列名),由于joins、group by order by等原因,我不能在主查询中使用limit。

【问题讨论】:

  • 为什么列列表不可能
  • 好吧,您必须列出所有列名以及不明确列的供应和别名。
  • 您的内部查询中是否有任何类型的分组/包含子句?如果没有,为什么不将limit 1000 添加到您的第一个查询中?
  • 人们很少需要使用SELECT *,并且在生产代码中使用它从不是一个好主意,而且几乎在所有情况下都是只是懒惰。我敢打赌,自从您提出这个问题后的 42 分钟内(我评论时没有答案),您本可以写出您需要的所有列。这样做的好处不仅是消除了重复列错误,它还可以在未来证明您的列位置不受 DDL 更改(例如添加新列或删除列)的影响,它还将减少服务器上的 I/O 和网络流量。
  • 多年来,我从未遇到过需要在一个查询中加入 50 个表。

标签: mysql sql


【解决方案1】:

您收到错误的原因是别名 AS X。但问题确实是你使用了*,而不是列出你想要的字段。

在第一个查询中,SELECT * 实际上会产生如下字段:

A.id, A.name, A.description, B.id, B.name, B.date_started, C.id, C.name, C.isDeleted

这很好用,除非您尝试直接通过名称引用字段并且不使用它的别名。无论哪种方式,您的 SQL 引擎都不会对此产生问题,但无论您对结果集做什么,都可能仍然存在问题。

但是,当您将查询移动到子查询中并将结果命名为 AS X 时,您最终会得到:

X.id, X.name, X.description, X.id, X.name, X.date_started, X.id, X.name, X.isDeleted

现在您可以看到它为什么抱怨了。您可以看到为什么使用* 也不好,因为这种组合可能会工作一段时间,然后您将一个新字段添加到现有表中,与另一个表相同,然后砰,您每次查询这两个表都写过,现在需要重写。

【讨论】:

    【解决方案2】:

    我通过自加入修复了它:

    SELECT * FROM A
    LEFT JOIN B ON B.x = A.y
    LEFT JOIN C ...
    JOIN (
        SELECT id FROM (
            SELECT id FROM A 
            WHERE ....
            GROUP BY ... 
            ORDER BY ...
        ) AS A1 WHERE 1 LIMIT 1000
    ) AS A2 ON A2.id = A.id
    WHERE 1
    

    MySQL 执行速度非常快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 2016-10-24
      • 1970-01-01
      相关资源
      最近更新 更多