使用比较运算符比较 postgres 中的字符串?
Comparing strings in postgres using comparison operators?
在许多编程语言中,您可以使用 >、>=、< 等运算符比较字符串...并且该语言将根据字母在字母表中的位置进行比较。
例如 PHP
if ('a' < 'b') {
echo 'Yes';
} else {
echo 'No';
}
> Yes
但是在 postgres 或 mysql
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END
FROM table
Output: null
我有一个 table 字符串,我需要通过 SQL 相互比较。
例如:
6.2(5a)
6.2(5b) -- 这将大于 6.2(5a)
或者
6.2(15) -- 这将大于 6.2(5a)
我想过使用正则表达式为字母分配一个数字,但是当没有字母时这会破坏比较。
纯粹在 SQL 中,您将如何处理?
注意:原来的答案是转移注意力的。
一个简单的比较,逐个字符排序。
select 'a1' < 'a9'; -- true because 'a' = 'a' and '1' < '9'.
...但很快就开始了。
select 'a10' < 'a9'; -- also true for the same reason.
您想要的是 natural sort,其中字符串部分作为字符串进行比较,数字作为数字进行比较。在 SQL 中进行自然排序并不是最简单的事情。您要么需要固定的字段宽度来分别对每个子字符串进行排序,要么可能需要使用正则表达式...
幸运的是 pg_natural_sort_order,一个实现高效自然排序的 Postgres 扩展。
如果您无法安装扩展,您可以使用 2kan 的 btrsort 等存储过程。
CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$
SELECT
CASE WHEN ~ '^[^0-9]+' THEN
COALESCE( SUBSTR( , LENGTH(SUBSTRING( FROM '[^0-9]+'))+1 ), '' )
ELSE
COALESCE( SUBSTR( , LENGTH(SUBSTRING( FROM '[0-9]+'))+1 ), '' )
END
$$ LANGUAGE SQL;
CREATE FUNCTION btrsort(text) RETURNS text AS $$
SELECT
CASE WHEN char_length()>0 THEN
CASE WHEN ~ '^[^0-9]+' THEN
RPAD(SUBSTR(COALESCE(SUBSTRING( FROM '^[^0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit())
ELSE
LPAD(SUBSTR(COALESCE(SUBSTRING( FROM '^[0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit())
END
ELSE
END
;
$$ LANGUAGE SQL;
虽然它没有提供比较运算符,但我不会假装理解它。这允许您在 order by
.
中使用它
select * from things order by btrsort(whatever);
为了防止自然排序的查询在大型 table 上变成泥泞,you can create a btree index on the result of that function。
create index things_whatever_btrsort_idx ON things( btrsort(whatever) );
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END
FROM table
Output: null
如果table 为空,这只会输出任何内容。您不需要 table 来测试 select 语句。
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END -- yes
在许多编程语言中,您可以使用 >、>=、< 等运算符比较字符串...并且该语言将根据字母在字母表中的位置进行比较。
例如 PHP
if ('a' < 'b') {
echo 'Yes';
} else {
echo 'No';
}
> Yes
但是在 postgres 或 mysql
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END
FROM table
Output: null
我有一个 table 字符串,我需要通过 SQL 相互比较。
例如: 6.2(5a) 6.2(5b) -- 这将大于 6.2(5a) 或者 6.2(15) -- 这将大于 6.2(5a)
我想过使用正则表达式为字母分配一个数字,但是当没有字母时这会破坏比较。
纯粹在 SQL 中,您将如何处理?
注意:原来的答案是转移注意力的。
一个简单的比较,逐个字符排序。
select 'a1' < 'a9'; -- true because 'a' = 'a' and '1' < '9'.
...但很快就开始了。
select 'a10' < 'a9'; -- also true for the same reason.
您想要的是 natural sort,其中字符串部分作为字符串进行比较,数字作为数字进行比较。在 SQL 中进行自然排序并不是最简单的事情。您要么需要固定的字段宽度来分别对每个子字符串进行排序,要么可能需要使用正则表达式...
幸运的是 pg_natural_sort_order,一个实现高效自然排序的 Postgres 扩展。
如果您无法安装扩展,您可以使用 2kan 的 btrsort 等存储过程。
CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$
SELECT
CASE WHEN ~ '^[^0-9]+' THEN
COALESCE( SUBSTR( , LENGTH(SUBSTRING( FROM '[^0-9]+'))+1 ), '' )
ELSE
COALESCE( SUBSTR( , LENGTH(SUBSTRING( FROM '[0-9]+'))+1 ), '' )
END
$$ LANGUAGE SQL;
CREATE FUNCTION btrsort(text) RETURNS text AS $$
SELECT
CASE WHEN char_length()>0 THEN
CASE WHEN ~ '^[^0-9]+' THEN
RPAD(SUBSTR(COALESCE(SUBSTRING( FROM '^[^0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit())
ELSE
LPAD(SUBSTR(COALESCE(SUBSTRING( FROM '^[0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit())
END
ELSE
END
;
$$ LANGUAGE SQL;
虽然它没有提供比较运算符,但我不会假装理解它。这允许您在 order by
.
select * from things order by btrsort(whatever);
为了防止自然排序的查询在大型 table 上变成泥泞,you can create a btree index on the result of that function。
create index things_whatever_btrsort_idx ON things( btrsort(whatever) );
SELECT CASE WHEN 'a' < 'b' THEN 'yes' END FROM table Output: null
如果table 为空,这只会输出任何内容。您不需要 table 来测试 select 语句。
SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END -- yes