别名字段上的 Postgres 排序规则

Posted

技术标签:

【中文标题】别名字段上的 Postgres 排序规则【英文标题】:Postgres collation on aliased field 【发布时间】:2015-09-18 11:27:24 【问题描述】:

我有下表:

CREATE TABLE public_bodies
  ("id" int, "name" varchar(46))
;

INSERT INTO public_bodies
  ("id", "name")
VALUES
  (1, 'Ytre Helgeland District Psychiatric Centre'),
  (2, 'Åfjord Municipality'),
  (3, 'Østfold Hospital')
;

我想运行这个查询:

SELECT public_bodies.id, public_bodies.name AS display_name
FROM public_bodies
ORDER BY display_name COLLATE "en_US";

但我收到此错误:

ERROR:  column "display_name" does not exist
LINE 3: ORDER BY display_name COLLATE "en_US";
                 ^

按表名排序可以正常工作:

SELECT public_bodies.id, public_bodies.name AS display_name
FROM public_bodies
ORDER BY public_bodies.name COLLATE "en_US";

--  id |        display_name
-- ----+--------------------------------------------
--   2 | Åfjord Municipality
--   3 | Østfold Hospital
--   1 | Ytre Helgeland District Psychiatric Centre

按别名排序也可以:

SELECT public_bodies.id, public_bodies.name AS display_name
FROM public_bodies
ORDER BY display_name;

--  id |        display_name
-- ----+--------------------------------------------
--   2 | Åfjord Municipality
--   3 | Østfold Hospital
--   1 | Ytre Helgeland District Psychiatric Centre

在分配别名之前应用COLLATE,但我不明白为什么这与ORDER_BY 之后的整理不同。

SELECT public_bodies.id, public_bodies.name COLLATE "en_US" AS display_name
FROM public_bodies
ORDER BY display_name;

--  id |        display_name
-- ----+--------------------------------------------
--   2 | Åfjord Municipality
--   3 | Østfold Hospital
--   1 | Ytre Helgeland District Psychiatric Centre

Postgres 版本:

SELECT version();
                                               version
-------------------------------------------------------------------------------------------------------------
 PostgreSQL 9.1.12 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit

我在 SQL fiddle (Postgres 9.3) 上得到了相同的结果。

为什么 Postgres 不能对别名字段进行整理?

【问题讨论】:

在 Postgresql 中你可能根本不能在 order 子句中使用别名 刚刚更新了问题 - 按别名排序而不进行任何排序都可以。 闻起来像虫子。您是否在当前版本 9.4.4 中尝试过? 9.4.4 也不行。 【参考方案1】:

这是定义语言的方式。 COLLATE 子句适用于表达式,这种情况不符合条件。

“表达式”是指一些运算符、函数、变量标识符、文字等的集合,它们组合起来产生一个输出值。换句话说,产生价值的“事物”的一般类,允许作为函数参数、SELECT 字段定义、VALUES 列表等出现。

COLLATE 子句可以附加到表达式,并且表达式可能出现在ORDER BY 列表中,但这不是ORDER BY 列表中允许的唯一 事物;您也可以包含names or positions of output columns,但解析器会将它们视为不同的情况。

需要区别对待的原因是查询的输出字段标识符在评估表达式时不在scope中;这就是为什么像ORDER BY display_name || 'x' 这样的东西会返回column "display_name" does not exist。为了解决这个问题,在尝试表达式评估之前,ORDER BY 列表中的裸字段名称会与输出列表进行比较,但结果是,在此上下文中,没有比裸字段名称更复杂的了(其中包括附COLLATE子句)。

【讨论】:

以上是关于别名字段上的 Postgres 排序规则的主要内容,如果未能解决你的问题,请参考以下文章

postgres - 无法创建排序规则

在 Postgres 上更改排序规则(保持编码)是不是安全?

使用 pg_dump 将 Postgres 从 Windows 迁移到 Linux 时如何选择正确的排序规则来创建数据库?

mysql汉字排序规则

java实现按对象某个字段排序,排序字段和规则自定义

mysql设置字段的排序规则对大小写敏感