这里有一个解决方案:
* 这里的好处是当你必须经常输入查询时,CTE 仍然是一个不错的选择
您只需select * from data order by json_weight(json_column,base_value);
为了能够做到这一点,请创建json_max、json_weight、json_maxdigits 和json_pad 这四个函数,并在 order by 子句中使用它们:
delimiter //
create or replace function json_max(j json) returns float deterministic
begin
declare l int;
declare mv float;
declare v float;
set l = json_length(j);
for i in 0..l-1 do
set v = abs(json_value(j,concat('$[',i,']')));
if (mv is null) or (v > mv) then
set mv = v;
end if;
end for;
return mv;
end
//
create or replace function json_weight(j json, base int) returns float deterministic
begin
declare l int;
declare w float;
set w = 0;
set l = json_length(j);
for i in 0..l-1 do
set w = w + pow(base,-i) * json_value(j,concat('$[',i,']'));
end for;
return w;
end
//
create or replace function json_maxdigits(j json) returns int deterministic
return length(cast(floor(abs(json_max(j))) as char(16)))
//
create or replace function json_pad(j json, digitcount int) returns varchar(512) deterministic
begin
declare l int;
declare v int;
declare w varchar(512);
set w = '';
set l = json_length(j);
for i in 0..l-1 do
set v = json_value(j,concat('$[',i,']'));
set w = concat(w, if(v>=0,'0','-'), lpad(v, digitcount, 0));
end for;
return w;
end
//
delimiter ;
然后按如下方式使用它们:
select * 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`
) data order by json_weight(`array`,max(json_max(`array`)) over ());
-- or if you know that 11 is the max value:
--) data order by json_weight(`array`,11);
-- alternative method:
--) data order by json_pad(`array`,max(json_maxdigits(`array`)) over ());
-- alternative method and you know that only two digits are enough to represent numbers in the array:
--) data order by json_pad(`array`,2);
解释:
json_max 为您提供 json_array 中的最大绝对值:
select json_max('[22,33,-55]'); -- 55
json_maxdigits 为您提供 json_array 中的最大位数(绝对数):
select json_maxdigits('[21,151,-4]'); -- 3
json_weight 将您的 json 数组转换为等效浮点值,其中数组的每个数字都等效于您指定为参数的基数中的一个数字:
select json_weight('[1,3,5,7]', 10); -- 1.357
select json_weight('[1,0,1]', 2); -- 1.25 (like binary floats)
json_pad 将您的 json 数组转换为一串零填充数字,其中包含减号信号作为额外符号以保证负序(或额外符号 0 否则因为 + 小于 - in ascii 顺序):
select json_pad('[1,-3,15,7]', 2); --'001-03015007'
您可以使用浮动权重或填充字符串对查询结果集进行排序。提供这两个选项的原因是:
- 当您有长 json 数组但支持浮点数时,浮点权重会失去精度
- 填充字符串具有很高的精度,此处设置为 512 位,您甚至可以增加此数字,但它们不提供浮点支持(无论如何您都没有要求)。
如果您使用浮动重量,则必须设置基础。您可以手动设置它或使用最大的数字作为基数,通过使用max(json_max(column_name)) over () 获得。如果您使用小于该最大值的基值,则可能会得到不一致的结果,如果您使用的数字太高,则会失去精度。
类似地,当使用填充字符串进行排序时,您必须提供最大绝对值消耗的最大位数(-35 将是 2 个绝对数字)。
注意:这些函数适用于早期版本的 MariaDB,但仍不支持 json_table 函数。