abe*_*bop 1 postgresql collation datatypes cast
有人可以解释这种神秘的 Postgres 行为吗?我正在psql命令行执行以下查询。
mydb=> select '20150526' > '2015-05-25';
-[ RECORD 1 ]
?column? | t
mydb=> select '20150526' > '2015-05-26';
-[ RECORD 1 ]
?column? | f
mydb=> select '20150526' > '2015-05-27';
-[ RECORD 1 ]
?column? | f
Run Code Online (Sandbox Code Playgroud)
如果 Postgres 实际上是直接比较字符串,则这三个值要么为真,要么为假,这取决于字符排序的定义方式。这似乎表明 Postgres 试图在比较之前将字符串转换为日期,大概是基于对格式的一些启发。然而:
mydb=> select '20150526' < '2015-05-27';
-[ RECORD 1 ]
?column? | t
mydb=> select '20150526' < '2015-05-26';
-[ RECORD 1 ]
?column? | t
mydb=> select '20150526' < '2015-05-25';
-[ RECORD 1 ]
?column? | f
Run Code Online (Sandbox Code Playgroud)
请注意,如果将启发式解释为日期,则中间查询的结果是不正确的!相反的问题发生在>=操作员身上。这在我正在使用的触发器函数中导致了一个极其微妙的错误。
所以,有两个谜团:
<和>=运算符的结果是错误的。这似乎是一个错误。是什么让你觉得你在比较日期?
实际上,您正在比较字符串文字- 在没有强制转换上下文和任何显式强制转换的情况下 - 默认为text:
SELECT '20150526' > '2015-05-26' AS text2text
, '20150526'::date > '2015-05-26'::date AS date2date;
text2text | date2date
----------+----------
t | f
Run Code Online (Sandbox Code Playgroud)
尝试:
SELECT pg_typeof(col) FROM (VALUES ('20150527')) t(col); -- no cast
pg_typeof
---------
text
Run Code Online (Sandbox Code Playgroud)
text值比较的结果取决于您的语言环境,准确地说取决于COLLATION规则。要查看COLLATION会话的默认值:
SHOW lc_collate;
Run Code Online (Sandbox Code Playgroud)
COLLATION也可以按列甚至每个表达式设置。要查看COLLATION任何表达式的实际使用collation for (any)构造:
SELECT collation for (my_column) FROM tbl LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
要测试字符串在您的语言环境中的排序方式:
SELECT *
FROM (
VALUES
('20150526')
, ('2015-05-25')
, ('20150525')
, ('2015-05-26')
, ('20150527')
, ('2015-05-27')
) t(col)
ORDER BY col; -- COLLATE "C"
Run Code Online (Sandbox Code Playgroud)
通过附加COLLATE "C"到,将其与纯字节值的排序顺序进行比较ORDER BY。要查看与不同的比较结果COLLATION:
SELECT '20150526' > '2015-05-26' COLLATE "C" AS text2text_c;
Run Code Online (Sandbox Code Playgroud)