我正在经历将可怕的遗留数据库规范化的痛苦,并且发现了我认为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表达式,而不同聚合返回的行数多于预期.sort-by表达式中的列不在选择列表中。 “
即。有问题的查询现在会导致错误,因为结果不正确。
答案 0 :(得分:6)
我看到的问题是,第二个查询在location
中有一列(ORDER BY
),但未包含在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
应在SELECT
和DISTINCT
之后处理。因此,原始表格中的两行或更多行可能具有相同的thing_id
和thing_name
但不同的location
。这些行将折叠为一行。因此,没有用于订购的位置值。即使有(一个隐藏的位置价值)保留,它应该是多少?
SELECT DISTINCT
和SELECT ALL
重写 GROUP 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 ;
答案 1 :(得分:3)
不,order by
不会影响返回的行数。
如果你说的是真的那将是一个非常奇怪和根本的错误。我将三重(然后四倍)检查两个查询的返回列,以确保在向Ingres发送电子邮件之前,绝对确保这不是一个简单的用户错误。
修改强> 的
实际上,我也会尝试在备份数据库上运行查询。如果您没有可用的备份,您可以通过复制您拥有的数据库(如果Ingres支持该数据库)而逃脱。
我之前有过查询,在有错误硬件的机器上返回无意义的结果。这肯定是你想要检查的东西。
答案 2 :(得分:3)
由于SQL中的操作顺序是:
FROM > WHERE > GROUP BY > HAVING > SELECT > ORDER BY
这似乎确实是一个错误。它是哪个DBMS?
答案 3 :(得分:0)
如果将location
添加到第一个查询,则两者都将返回相同的行数。第二个查询返回更多行的原因是因为在该查询中您没有选择location
。
如前所述,一些RDBMS不允许它,Ingres确实如此。可能是因为 SQL标准不禁止它?。