Postgres 12 不区分大小写的比较

Posted

技术标签:

【中文标题】Postgres 12 不区分大小写的比较【英文标题】:Postgres 12 case-insensitive compare 【发布时间】:2020-03-28 19:58:17 【问题描述】:

我正在尝试将 C# 应用程序 (+EF6) 使用的 SQL Server DB 移动到 Postgres 12,但我没有太多运气让不区分大小写的字符串比较正常工作。现有的 SQL Server db 使用 SQL_Latin1_General_CP1_CI_AS 排序规则,这意味着所有 WHERE 子句都不必担心大小写。

我了解 CIText 是以前执行此操作的方法,但现在已被非确定性排序规则所取代。

我创建了这样一个排序规则;

CREATE COLLATION ci (provider = icu, locale = 'und-u-ks-level2', deterministic = false);

当它按列应用于 CREATE TABLE 时,它确实有效 - 忽略大小写。

CREATE TABLE casetest (
id serial NOT NULL,
code varchar(10) null COLLATE "ci",
CONSTRAINT "PK_id" PRIMARY KEY ("id"));

但是根据我的阅读,它必须应用于每个 varchar 列,并且不能在整个数据库中全局设置。

这是正确的吗?

由于混乱,我不想在任何地方使用 .ToLower() 并且列上的任何索引都不会被使用。

我尝试修改 pg_collat​​ion 中预先存在的“默认”排序规则以匹配“ci”排序规则的设置,但没有效果。

提前致谢。 PG

【问题讨论】:

【参考方案1】:

你没看错。 ICU 排序规则(目前)不能用作数据库默认排序规则,但必须在列定义中使用。

这个限制很烦人,而且不是事物的本质。它可能会在未来的某个版本中被取消。

您可以使用DO 语句来更改所有字符串列的排序规则:

DO
$$DECLARE
   v_table  regclass;
   v_column name;
   v_type   oid;
   v_typmod integer;
BEGIN
   FOR v_table, v_column, v_type, v_typmod IN
      SELECT a.attrelid::regclass,
             a.attname,
             a.atttypid,
             a.atttypmod
      FROM pg_attribute AS a
         JOIN pg_class AS c ON a.attrelid = c.oid
      WHERE a.atttypid IN (25, 1042, 1043)
        AND c.relnamespace::regnamespace::name
            NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
   LOOP
      EXECUTE
         format('ALTER TABLE %s ALTER %I SET DATA TYPE %s COLLATE ci',
                v_table,
                v_column,
                format_type(v_type, v_typmod)
         );
   END LOOP;
END;$$;

【讨论】:

在 PostgreSQL Commitfest 2019-11 上,feature 被“返回并提供反馈”。所以我猜它不会来。 @ReinState 另一个补丁可能会在未来出现;人们都知道这是一个缺点。 这似乎是商业“EDB Postgres Advanced Server”的一个功能。您可以为每个数据库设置默认 ICU 排序规则,例如 CREATE DATABASE collation_db TEMPLATE template0 ENCODING 'UTF8' ICU_SHORT_FORM = 'AN_CU_EX_NX_LROOT';。 old docs(Other versions and formats) 中有很好的例子。但是没有提到不确定的排序规则。 如果您希望查询只工作™ 不区分大小写,您可以使用此脚本将列类型转换为citext。这是一个 additional supplied module 在进行查询之前调用 lower() 。通过CREATE EXTENSION citext; 导入一次并将格式行更改为format('ALTER TABLE %s ALTER COLUMN %I SET DATA TYPE CITEXT'。这样做的好处是 LIKE, ILIKE and ~* keep working 并通过 LIKE 语句启用可移植 SQL。

以上是关于Postgres 12 不区分大小写的比较的主要内容,如果未能解决你的问题,请参考以下文章

MS Access + Postgres 口音/不区分大小写的可编辑过滤器

Django 中的唯一模型字段和区分大小写(postgres)

Django 中的唯一模型字段和区分大小写(postgres)

如何在 Postgres 中删除区分大小写?

实体框架核心 - 包含区分大小写还是不区分大小写?

字符串的字典比较[不区分大小写]