如果要求不同的值,则mysql group_concat按DESC意外行为排序

时间:2018-03-03 17:58:53

标签: mysql

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');

现在考虑查询

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

正如预期的那样,它会吐出foo;baz 问题是,为什么

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

输出baz;foo

看起来Mysql是如何进行提升排序然后将其转换为DESC 我希望从(4,'foo'), (3,'baz')返回结果。

数据库版本= 10.2.12-MariaDB-log

编辑:

如果涉及更多数据,则更加引人注目: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

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

- > bar;baz;foo ??     我确实在这里预期foo;bar;baz

如果不需要DISTINCT,无论是ASC还是DESC,数据库都会按预期返回。

2 个答案:

答案 0 :(得分:1)

看起来像你的第一个例子:

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

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

根据检索顺序1的行为是在2之前,所以你得到foo;bar

在我看来,你需要:

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

<强> DBFiddle Demo

修改

这与以下情况相同:

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

请注意,对于其他数据库,此查询将返回错误:

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

更多信息:SELECT DISTINCT and ORDER BY in MySQL

基于What's New in SQL:2016LISTAGG(DISTINCT ... )

  

listagg(distinct ...)

     

如果按汇总值排序:listagg(distinct X ,...)在组内(按 X 排序)

答案 1 :(得分:0)

在进行了一些调查后,结果非常简单,所有返回的结果 - 预期或意外 - 确实是正确的。

MySQL 5.7 Reference Manual中的神奇句子是

  

在选择值后发生结果集排序

所以

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

首先执行作业的DISTINCT部分并将其作为中间结果:

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

现在引擎获取此结果并对其进行排序。 ASC或DESC按要求。