简体   繁体   English

如果询问不同的值,MySQL group_concat 命令按 DESC 意外行为

[英]Mysql group_concat order by DESC unexpected behaviour if asking distinct values

CREATE OR REPLACE TABLE `tmp` (
  `ord` int(5) unsigned NOT NULL DEFAULT 10000,
  `val` varchar(50) CHARACTER SET utf8 COLLATE utf8_estonian_ci NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `tmp` (`ord`, `val`)
VALUES (1,'foo'), (2,'baz'), (3,'baz'), (4,'foo');

Now consider the query现在考虑查询

-- 1) Example with ASC sorting
select group_concat( distinct val 
ORDER BY ord  ASC SEPARATOR ';') from tmp;

As expected, it spits out foo;baz .正如预期的那样,它吐出foo;baz
Question is, why问题是,为什么

-- 2) Example with DESC sorting
select group_concat( distinct val 
ORDER BY ord DESC SEPARATOR ';') from tmp;

outputs baz;foo ?输出baz;foo ?

It looks like if Mysql performed ascending sort and then just reversed it for DESC.看起来如果 Mysql 执行升序排序,然后只是将其反转为 DESC。
I would expect to return results from (4,'foo'), (3,'baz') .我希望从(4,'foo'), (3,'baz')返回结果。

Database version = 10.2.12-MariaDB-log数据库版本 = 10.2.12-MariaDB-log

EDIT:编辑:

It's even more noticeable, if there is a little more data involved: DBFiddle如果涉及的数据多一点,那就更引人注目了: DBFiddle

INSERT INTO `tmp` (`ord`, `val`)
VALUES (1,'foo'), (2,'baz'), (3,'baz'), (4,'bar'), (5,'foo');

select group_concat( distinct val 
ORDER BY ord ASC SEPARATOR ';') from tmp ;

--> foo;baz;bar --> foo;baz;bar

select group_concat( distinct val 
ORDER BY ord DESC SEPARATOR ';') from tmp;

--> bar;baz;foo ?? --> bar;baz;foo ??
I really did expected foo;bar;baz here.我真的期待foo;bar;baz在这里。

If DISTINCT is not required, database returns as expected no matter if ASC or DESC.如果不需要 DISTINCT,则无论是 ASC 还是 DESC,数据库都会按预期返回。

It looks like for your first example:对于您的第一个示例,它看起来像:

select group_concat( distinct val 
ORDER BY ord  ASC SEPARATOR ';') from tmp;

-- order
(1,'foo'), (2,'baz')

And it behaves according to order of retrieval 1 is before 2 so you get foo;bar .它根据检索顺序 1 在 2 之前运行,所以你得到foo;bar

In my opinion you need:在我看来你需要:

select group_concat( distinct val ORDER BY val  ASC SEPARATOR ';') from tmp;

DBFiddle Demo DBFiddle 演示


EDIT:编辑:

This is the same situation like:这与以下情况相同:

CREATE TABLE tmp(ord int,  val varchar(10)) ;
INSERT INTO tmp (ord, val) VALUES (1,'foo'), (2,'baz'), (3,'baz'), (4,'foo');

SELECT DISTINCT val
FROM tmp
ORDER BY ord;

DBFiddle Demo2 DBFiddle Demo2

Please note that for other databases this query will return error:请注意,对于其他数据库,此查询将返回错误:

PostgreSQL:
ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
LINE 3: ORDER BY ord;

SQL Server:
Msg 145 Level 15 State 1 Line 1
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.

Oracle:
ORA-01791: not a SELECTed expression

MySQL when SET @@sql_mode = 'ONLY_FULL_GROUP_BY';
ORDER BY clause is not in SELECT list, references column 'ord' 
which is not in SELECT list; this is incompatible with DISTINCT

More info: SELECT DISTINCT and ORDER BY in MySQL更多信息: MySQL 中的 SELECT DISTINCT 和 ORDER BY


Based on LISTAGG(DISTINCT ... ) from What's New in SQL:2016 :基于SQL:2016 中的新增功能中的LISTAGG(DISTINCT ... )

listagg(distinct ...) listagg(不同的...)

If ordered by the aggregated values: listagg(distinct X ,…) within group (order by X )如果按聚合值排序: listagg(distinct X ,...) 组内(按X排序)

After investigating some more, it turns out quite simple and all returned results - expected or unexpected - are correct indeed.在进一步调查之后,结果非常简单,并且所有返回的结果 - 预期的或意外的 - 确实是正确的。

The magical sentence in MySQL 5.7 Reference Manual is MySQL 5.7 参考手册中神奇的一句话是

Result set sorting occurs after values have been chosen结果集排序发生在选择值之后

so所以

select group_concat( distinct val 
ORDER BY ord XXSC SEPARATOR ';') from tmp;

does the DISTINCT part of the job first and gets this as intermediate result:首先执行作业的 DISTINCT 部分并将其作为中间结果:

-- unordered
(1,'foo'), (2,'baz')

Now engine takes this result and orders it.现在引擎接受这个结果并对其进行排序。 ASC or DESC as requested.根据要求 ASC 或 DESC。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM