postgresql 使用比较运算符比较 postgres 中的字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40601324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:20:03  来源:igfitidea点击:

Comparing strings in postgres using comparison operators?

postgresqlnatural-sort

提问by bakamike

In many programming languages you can compare strings using operators like >, >=, < etc...and the language will base the comparison on the position of the letter in the alphabet.

在许多编程语言中,您可以使用 >、>=、< 等运算符来比较字符串,并且该语言将根据字母在字母表中的位置进行比较。

For example in PHP

例如在 PHP 中

if ('a' < 'b') {
    echo 'Yes';
} else {
    echo 'No';
}
> Yes

However in postgres or mysql

但是在 postgres 或 mysql 中

SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END
FROM table
Output: null

I have a table with strings that I need to compare against each other through SQL.

我有一个包含字符串的表,需要通过 SQL 相互比较。

For example: 6.2(5a) 6.2(5b) -- this would be greater than 6.2(5a) Or 6.2(15) -- this would be greater than 6.2(5a)

例如: 6.2(5a) 6.2(5b) -- 这将大于 6.2(5a) 或 6.2(15) -- 这将大于 6.2(5a)

I thought of assigning a number to a letter using a regexp but then that would break the comparisons when there are no letter.

我想过使用正则表达式为字母分配一个数字,但是当没有字母时,这会破坏比较。

How would you go about this purely in SQL?

您将如何纯粹在 SQL 中解决这个问题?

回答by Schwern

NOTE: The original answer went off on a red herring.

注意最初的答案是在一个红鲱鱼上

A simple comparison sorts character by character.

一个简单的比较按字符排序。

select 'a1' < 'a9'; -- true because 'a' = 'a' and '1' < '9'.

...but quickly goes to pot.

......但很快就去锅了。

select 'a10' < 'a9'; -- also true for the same reason.

What you want is a natural sortwhere the string parts are compared as strings and the numbers are compared as numbers. Doing a natural sort in SQL is not the easiest thing. You either need fixed field widths to sort each substring separately, or maybe something with regexes...

您想要的是一种自然排序,其中将字符串部分作为字符串进行比较,并将数字作为数字进行比较。在 SQL 中进行自然排序并不是最简单的事情。您需要固定的字段宽度来分别对每个子字符串进行排序,或者可能需要使用正则表达式...

Fortunately there's pg_natural_sort_order, a Postgres extension that implements an efficient natural sort.

幸运的是pg_natural_sort_order是一个 Postgres 扩展,它实现了一种高效的自然排序。

If you can't install extensions you can use a stored procedure like btrsortby 2kan.

如果你不能安装扩展,你可以使用像btrsortby 2kan这样的存储过程。

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;

Though it doesn't provide a comparison operator and I'm not going to pretend to understand it. This allows you to use it in an order by.

虽然它不提供比较运算符,我也不会假装理解它。这允许您在order by.

select * from things order by btrsort(whatever);

To prevent your naturally sorted queries from turning to mud on large tables, you can create a btree index on the result of that function.

为了防止自然排序的查询在大表上变成泥,您可以在该函数的结果上创建一个 btree 索引

create index things_whatever_btrsort_idx ON things( btrsort(whatever) );


SELECT
  CASE WHEN 'a' < 'b' THEN 'yes' END
  FROM table
  Output: null
SELECT
  CASE WHEN 'a' < 'b' THEN 'yes' END
  FROM table
  Output: null

This will only output nothing if the table is empty. You don't need a table to test select statements.

如果表为空,这只会输出任何内容。您不需要表来测试选择语句。

SELECT
CASE WHEN 'a' < 'b' THEN 'yes' END  -- yes