Jon*_*eir 5 mysql json sql-order-by mariadb mysql-json
PostgreSQL 允许按数组对行进行排序。它比较每个数组的第一个值,然后比较第二个值,依此类推(fiddle):
select array[2, 4] as "array"
union
select array[10] as "array"
union
select array[2, 3, 4] as "array"
union
select array[10, 11] as "array"
order by "array"
Run Code Online (Sandbox Code Playgroud)
| 大批 |
|---|
| [2,3,4] |
| [2, 4] |
| [10] |
| [10, 11] |
MySQL 和 MariaDB 上最接近的等效项似乎是JSON 数组。
MySQL 显然或多或少随机地按长度对数组进行排序( fiddle):
select json_array(2, 4) as `array`
union
select json_array(10) as `array`
union
select json_array(2, 3, 4) as `array`
union
select json_array(10, 11) as `array`
order by `array`
Run Code Online (Sandbox Code Playgroud)
| 大批 |
|---|
| [10] |
| [2, 4] |
| [10, 11] |
| [2,3,4] |
MariaDB 有点按值排序,但执行不正确(fiddle)。整数像字符串一样排序(10before 2),具有相同开头的数组则相反([10, 11]before [10]):
select json_array(2, 4) as `array`
union
select json_array(10) as `array`
union
select json_array(2, 3, 4) as `array`
union
select json_array(10, 11) as `array`
order by `array`
Run Code Online (Sandbox Code Playgroud)
| 大批 |
|---|
| [10, 11] |
| [10] |
| [2,3,4] |
| [2, 4] |
有没有办法在 MySQL 和/或 MariaDB 上复制 PostgreSQL 的数组排序?
数组可以有任意长度,但我不知道最大长度。
我目前看到的唯一解决方法/黑客是将数组连接0成一个字符串,并用s 将值左侧填充到相同的长度:等002.004。010.011
对我来说这看起来像是一个错误。根据文档
如果两个 JSON 数组具有相同的长度并且数组中相应位置的值相等,则它们相等。
如果数组不相等,则它们的顺序由第一个存在差异的位置的元素确定。该位置中值较小的数组首先排序。如果较短数组的所有值都等于较长数组中的相应值,则较短数组先排序。
但ORDER BY看起来根本不遵守这样的规则。
这是MySQL 8 和 5.7 的数据库小提琴
我正在使用CROSS JOIN显式比较来获得预期的顺序。
SELECT f.`array`, SUM(f.`array` > g.`array`) cmp
FROM jsons f
CROSS JOIN jsons g
GROUP BY f.`array`
ORDER BY cmp
;
Run Code Online (Sandbox Code Playgroud)
MySQL 5.7 还有一个观察结果,当使用子查询时,>正在执行诸如字符串比较之类的操作,需要再次转换JSON才能获得正确的结果,而 MySQL8 不需要这样做。
SELECT f.`array`, SUM(CAST(f.`array` AS JSON) > CAST(g.`array` AS JSON)) cmp
FROM (
select json_array(2, 4) as `array`
union
select json_array(10) as `array`
union
select json_array(2, 3, 4) as `array`
union
select json_array(10, 11) as `array`
) f
CROSS JOIN (
select json_array(2, 4) as `array`
union
select json_array(10) as `array`
union
select json_array(2, 3, 4) as `array`
union
select json_array(10, 11) as `array`
) g
GROUP BY f.`array`
ORDER BY cmp
;
Run Code Online (Sandbox Code Playgroud)
上面的内容在 MariaDB 中不起作用。
在MySQL中,JSON是根据json值进行比较的。在 MariaDB 中,JSON 字符串是普通字符串,并作为字符串进行比较。
下面的查询适用于 MariaDB
WITH RECURSIVE jsons AS (
select json_array(2, 4) as `array`
union
select json_array(10) as `array`
union
select json_array(2, 3, 4) as `array`
union
select json_array(10, 11) as `array`
),
maxlength AS (
SELECT MAX(JSON_LENGTH(`array`)) maxlength
FROM jsons
),
numbers AS (
SELECT 0 AS n
FROM maxlength
UNION ALL
SELECT n + 1
FROM numbers
JOIN maxlength ON numbers.n < maxlength.maxlength - 1
),
expanded AS (
SELECT a.`array`, b.n, JSON_EXTRACT(a.`array`, CONCAT('$[', b.n, ']')) v
FROM jsons a
CROSS JOIN numbers b
),
maxpadding AS (
SELECT MAX(LENGTH(v)) maxpadding
FROM expanded
)
SELECT a.`array`
FROM expanded a
CROSS JOIN maxpadding b
GROUP BY a.`array`
ORDER BY GROUP_CONCAT(LPAD(a.v, b.maxpadding, '0') ORDER BY a.n ASC)
Run Code Online (Sandbox Code Playgroud)