在许多编程语言中,您可以使用>,> =,<等运算符来比较字符串.等...语言将基于字母表中字母的位置进行比较. 例如在
PHP中
if ('a' < 'b') { echo 'Yes'; } else { echo 'No'; } > Yes
但是在postgres或MysqL中
SELECT CASE WHEN 'a' < 'b' THEN 'yes' END FROM table Output: null
例如:
6.2(5a)中
6.2(5b) – 这将大于6.2(5a)
要么
6.2(15) – 这将大于6.2(5a)
解决方法
大多数字符串比较默认为所谓的
ASCIIbetical sorting.它将每个字符转换为其ASCII编号(或者可能是UTF-8,其与前7位的ASCII重叠)然后进行排序.这看起来很好……
select 'a' < 'z'; -- true
……但很快就会出错.
select 'a' < 'Z'; -- false
这是因为所有大写字母都在ASCII和UTF-8中的所有小写字母之后.
解决这个问题的简单方法是通过在两侧调用upper或lower来规范化大小写.
select lower('a') < lower('Z'); -- true
ASCIIbetical排序的第二个问题是数字.再次,它开始很好……
select 'a9' < 'a1'; -- true
……但很快就去了锅.
select 'a9' < 'a10'; -- false
ASCIIbetical排序一次比较一个字符. ASCII 9(57)小于ASCII 1(49).
你想要的是一个natural sort,其中字符串部分作为字符串进行比较,数字作为数字进行比较.在sql中进行自然排序并不是最简单的事情.您需要固定的字段宽度来分别对每个子字符串进行排序,或者可能需要使用正则表达式…
幸运的是,pg_natural_sort_order是Postgres扩展,实现了高效的自然排序.
如果您无法安装扩展,则可以使用存储过程,例如2kan的btrsort.
CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$ SELECT CASE WHEN $1 ~ '^[^0-9]+' THEN COALESCE( SUBSTR( $1,LENGTH(SUBSTRING($1 FROM '[^0-9]+'))+1 ),'' ) ELSE COALESCE( SUBSTR( $1,LENGTH(SUBSTRING($1 FROM '[0-9]+'))+1 ),'' ) END $$LANGUAGE sql; CREATE FUNCTION btrsort(text) RETURNS text AS $$ SELECT CASE WHEN char_length($1)>0 THEN CASE WHEN $1 ~ '^[^0-9]+' THEN RPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[^0-9]+'),''),1,12),12,' ') || btrsort(btrsort_nextunit($1)) ELSE LPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[0-9]+'),' ') || btrsort(btrsort_nextunit($1)) END ELSE $1 END ; $$LANGUAGE sql;
虽然它没有提供比较运算符,但我不会假装理解它.这允许您按顺序使用它.
select * from things order by btrsort(whatever);
为防止自然排序的查询在大型桌子上变成泥,you can create a btree index on the result of that function.
create index things_whatever_btrsort_idx ON things( btrsort(whatever) );
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。