【问题标题】:Should an ORDER BY ever affect the number of rows returned a SELECT query?ORDER BY 是否应该影响返回 SELECT 查询的行数?
【发布时间】:2012-05-09 22:23:55
【问题描述】:

我正在经历规范化一个可怕的遗留数据库的痛苦,并且发现了我认为是 DBMS 的一个错误。

此查询按我的预期返回结果:

SELECT DISTINCT RIGHT(SQUEEZE(thing_id), 2) AS thing_id, TRIM(thing_name)
FROM thing
ORDER BY thing_id, thing_name;
(16 rows)

我第一次运行查询时,无意中在 ORDER BY 中使用了错误的列,如下所示:

SELECT DISTINCT RIGHT(SQUEEZE(thing_id), 2) AS thing_id, TRIM(thing_name)
FROM thing
ORDER BY thing_name, location;
(33 rows)

请注意,唯一要更改的是 ORDER BY,返回的行数从 16 增加到 33。它给出的结果不是查询指定的 DISTINCT。

我认为这是一个彻头彻尾的错误,但一位同事说这是正常的,因为当我们按“位置”订购时,它被选择了一个不可见的包含在结果中。

ORDER BY 是否应该影响 SELECT 查询中返回的行数?

编辑:我让另一个人查看查询并将查询复制到两个单独的文件中,然后对它们运行 diff 命令。 100% 确定这两个查询之间的唯一区别是 ORDER BY 中列出的列。

更新:Ingres 自发布补丁 14301 以来已修复错误:“错误 126640 (GENERIC) 使用 order-by 表达式和不同聚合的查询返回的行数比预期的多。order-by 表达式中的列不在选择列表中。 "

即有问题的查询现在将导致错误,因为结果不正确。

【问题讨论】:

  • 你能显示确切的查询吗?
  • @shiplu.mokadd.im 以上是确切的查询。我只是用“thing”替换了真实的公司名称,并删除了返回的数据。
  • 检查数据库是否损坏。例如,如果两个查询使用两个不同的索引并且其中一个已损坏,您将看到这种行为。
  • 或者,您可以尝试删除并重新创建表上的所有索引,或者制作表的副本并重试查询以排除损坏的原因。

标签: sql ingres


【解决方案1】:

我看到的问题是第二个查询在 ORDER BY 中有一个列 (location),它不包含在 SELECT DISTINCT 列表中。实际上这两个查询都是无效的 SQL(尽管 Ingres 似乎允许它们)。我将它们(所以第一个可以)简化为:

查询一(有效的SQL):

SELECT DISTINCT 
      thing_id 
    , thing_name
FROM thing
ORDER BY thing_id
       , thing_name ;

查询二(无效的SQL,应该报错):

SELECT DISTINCT 
      thing_id 
    , thing_name
FROM thing
ORDER BY thing_name
       , location;

为什么要报错?因为ORDER BY应该在SELECTDISTINCT之后处理。因此,原始表中的两行或多行可能具有相同的thing_idthing_name,但不同的location。这些行将折叠成一个。因此,没有用于排序的位置值。即使保留了(隐藏的位置值),它应该是众多中的哪一个?

SELECT DISTINCT 查询可以用SELECT ALLGROUP BY 重写(在这种情况下也无效):

SELECT ALL
      thing_id 
    , thing_name
FROM thing
GROUP BY thing_id 
       , thing_name
ORDER BY thing_name
       , location;

上述(查询 2)实际上确实在 PostgreSQL、SQL-Server 和 Oracle 中产生了错误。在SQL-Fiddle中测试它


从 Ingres 中第二个查询返回的错误行数,我猜测幕后发生的事情是他 location 被秘密保存在 SELECT 列表中,因此可以用于 ORDER BY然后删除。这与 DISTINCT 结合会导致非标准的错误行为:

SELECT DISTINCT 
      thing_id 
    , thing_name
   (, location         --- hidden column) 
FROM thing
ORDER BY thing_name
       , location;

你可以称它为错误或功能,没关系,只要你知道它一开始就不应该被允许。

似乎一年前在 Actian 论坛上报告了一个类似的问题:Problem with DISTINCT + ORDER BY 并且据说已修复。不知道他们指的是哪个版本,或者它是否已实际修复(以及“修复”的含义)。


如果您希望查询有效且行为符合您的预期,您可以使用如下所示的内容:

SELECT
      RIGHT(SQUEEZE(thing_id), 2)  AS squeezed_thing_id
    , TRIM(thing_name)             AS trimmed_thing_name 
    , MIN(location)                AS a_location            --- or MAX()
FROM 
    thing
GROUP BY 
      RIGHT(SQUEEZE(thing_id), 2)
    , TRIM(thing_name)     
ORDER BY 
      trimmed_thing_name
    , a_location ;                

【讨论】:

  • 我确实求助于打开了一本教科书,它说 ORDER BY 可以指定结果中没有出现的列,但是有些方言坚持认为 ORDER BY 只能引用出现在结果。所以在这种情况下,Ingres 允许它,而您提到的 DBMS 服务器不允许。
  • 在没有SELECT DISTINCTGROUP BY 的查询中,是的,我认为几乎所有(如果不是全部)DBMS 都允许任何列在ORDER BY 中。当有分组时,情况就大不相同了。而SELECT DISTINCT 是一种分组形式。
【解决方案2】:

由于SQL中的操作顺序是:

FROM > WHERE > GROUP BY > HAVING > SELECT > ORDER BY

这似乎确实是一个错误。它是哪个 DBMS?

【讨论】:

  • 正如标签所说,DBMS 是 Ingres。
  • 感谢@Mario,我选择了您的答案,因为您还指定了为什么 ORDER BY 不应影响这样的结果。
  • @rusty_turkey 谢谢。我还想说,可以从结果中删除行的唯一两个子句是 wherehaving,如果您指定“distinct”或者其余列为 NULL,则可能还有 select行。
  • @mario group by 影响行数,from 子句可以删除行,例如on(1=2)
  • 对于大多数 RDBMS,您可以将 > WINDOWING FUNCTIONS 添加到列表末尾
【解决方案3】:

不,order by 应该影响返回的行数。

如果你说的是真的,那将是一个非常奇怪和根本的错误。在给 Ingres 人发电子邮件之前,我会三倍(然后四倍)检查两个查询的返回列,以确保绝对这不是简单的用户错误。

编辑

实际上,我也会尝试在备份数据库上运行查询。如果您没有可用的备份,则可以通过复制您拥有的数据库(如果 Ingres 支持)而侥幸成功。

我之前在硬件故障的机器上遇到过查询返回无意义的结果。这肯定是您想要检查的内容。

【讨论】:

  • 我十亿检查了查询,因为我认为我要么疯了,要么对 SQL 一无所知。根据我原始帖子的编辑,我还将查询复制并粘贴到两个文件中,然后对它们进行了 unix diff 以确认。
【解决方案4】:

如果将location 添加到第一个查询中,则两者都将返回相同的行数。第二个查询返回更多行的原因是因为在该查询中您没有选择location。 如前所述,一些 RDBMS 不允许这样做,而 Ingres 允许。可能是因为SQL 标准没有禁止 ?.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多