我正在经历规范可怕的遗留数据库的痛苦,并且发现了我认为DBMS的一个错误.
此查询返回我期望的结果:
SELECT DISTINCT RIGHT(SQUEEZE(thing_id), 2) AS thing_id, TRIM(thing_name)
FROM thing
ORDER BY thing_id, thing_name;
(16 rows)
Run Code Online (Sandbox Code Playgroud)
我第一次运行查询时,无意中在ORDER BY中使用了错误的列,如下所示:
SELECT DISTINCT RIGHT(SQUEEZE(thing_id), 2) AS thing_id, TRIM(thing_name)
FROM thing
ORDER BY thing_name, location;
(33 rows)
Run Code Online (Sandbox Code Playgroud)
请注意,唯一要更改的是ORDER BY,并且返回的行数从16增加到33.它提供的结果不是查询指定的DISTINCT.
我相信这是一个彻头彻尾的错误,但是同事说这是正常的,因为当我们通过"位置"进行排序时,会在结果中选择一个无形的.
ORDER BY是否会影响SELECT查询中返回的行数?
编辑:我有另一个人查看查询,我将查询复制到两个单独的文件,然后对它们运行diff命令.100%确定两个查询之间的唯一区别是ORDER BY中列出的列.
更新:Ingres已发布修补程序14301,其中包含错误修正:"错误126640(GENERIC)查询具有order-by表达式,而不同聚合返回的行数超出预期.order-by表达式中的列不在选择列表中."
即有问题的查询现在会导致错误,因为结果不正确.
我看到的问题是第二个查询的列location中ORDER BY没有列()SELECT DISTINCT.实际上两个查询都是无效的SQL(尽管Ingres似乎允许它们).我简化了它们(所以第一个没问题):
查询一个(有效的SQL):
SELECT DISTINCT
thing_id
, thing_name
FROM thing
ORDER BY thing_id
, thing_name ;
Run Code Online (Sandbox Code Playgroud)
查询二(无效的SQL,应该产生错误):
SELECT DISTINCT
thing_id
, thing_name
FROM thing
ORDER BY thing_name
, location;
Run Code Online (Sandbox Code Playgroud)
它为什么要出错?因为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;
Run Code Online (Sandbox Code Playgroud)
上面的(查询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;
Run Code Online (Sandbox Code Playgroud)
您可以将其称为错误或功能,这没关系,只要您知道它应该首先被允许.
似乎一年前在Actian论坛上报道了一个类似的问题: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 ;
Run Code Online (Sandbox Code Playgroud)
由于SQL中的操作顺序是:
FROM > WHERE > GROUP BY > HAVING > SELECT > ORDER BY
Run Code Online (Sandbox Code Playgroud)
这似乎确实是一个错误。它是哪个数据库管理系统?