当字符串包含某些符号字符时神秘的Postgres字符串比较结果

问题描述 投票:0回答:2

当我尝试比较包含斜杠“/”或问号“?”的字符串时,我的 Postgres 服务器给了我非常混乱的结果。例如,在 psql 中我运行:

select ('/' < '1') as c1,
       ('/1' < '1') as c2,
       ('/////1' < '1') as c3,
       ('/1' < '2') as c4,
       ('/1' < '11') as c5;

结果是:

 c1 | c2 | c3 | c4 | c5
----+----+----+----+----
 t  | f  | f  | t  | t

所以

'/'
小于
'1'
,但
'/1'
大于
'1'
。事实上
'/1'
介于
'1'
'2'
之间,
'/////1'
也是如此。这不符合字典顺序。

但是,

'/1'
(正确地)小于
11
,这让我更加困惑。

我想看看

'/1'
是否被视为转义。于是我就跑了:

select length('/1');

我得到了

2
,这意味着 postgres 确实将
'/1'
视为两个字符的字符串。

当我将

/
替换为其他符号(例如
$
?
)时,也会发生同样的问题。

如果您有 docker,则可以通过在 docker 容器中运行 postgres 轻松重现此问题:

docker run postgres:11
docker exec  -it `docker ps | grep postgres:11 | cut -d' ' -f 1` psql -U postgres

然后尝试上面的 SQL。我尝试了 postgres 10 图像,行为是相同的。

当我将 VARCHAR 列与字符串文字进行比较时,真实的 SQL 也会发生同样的情况。这个问题让我抓狂,因为我需要编写正确的 SQL 来比较文件路径,其中显然包含许多“/”符号。

我搜索后没有找到任何讨论此问题的文档,因此这看起来不像是 postgres 的“官方功能”。按照字典顺序编写比较的正确方法是什么?

提前非常感谢。

sql postgresql collation
2个回答
2
投票

Postgres 使用操作系统的排序规则(在 Linux 上,由

glibc
提供)。所以你的结果取决于底层操作系统。

您可以使用

"C"
排序规则强制进行 ASCCI 比较(就像我在上面的示例中所做的那样):

select '/1' > '1' collate "C"

这似乎在所有平台上都一样工作。或者,您可以指定一个 ICU 排序规则,该排序规则在所有平台上也同样有效。


您提到您想要比较文件路径。仅在“名称”上执行此操作(忽略分隔符”)的一种方法是将路径转换为数组

string_to_array(filepath, '/')
,然后使用该数组进行排序或比较。


0
投票

我也遇到过同样的问题

select ('|' < 'x') as c1,
   ('|x' < 'x') as c2,
   ('|1' < 'x1') as c3,
   ('||' < 'x|') as c4,
   ('||1' < 'x|1') as c5;
c1 c2 c3 c4 c5
真实 真实 真实 真实 真实

将右侧的“x”替换为“0”

select ('|' < '0') as c1,
   ('|x' < '0') as c2,
   ('|1' < '01') as c3,
   ('||' < '0|') as c4,
   ('||1' < '0|1') as c5;
c1 c2 c3 c4 c5
真实 真实

这是在 Azure 上的 PostgreSQL 上 x86_64-pc-linux-gnu 上的 PostgreSQL 16.3,由 gcc (GCC) 11.2.0 编译,64 位

在 Windows 上,一切都很好。

© www.soinside.com 2019 - 2024. All rights reserved.