在扩展数组后进行转换时,我偶然发现unnest()
的奇怪行为。
使用unnest()有三种基本语法变体:
1)SELECT unnest('{1,NULL,4}'::int[]) AS i;
2)SELECT i FROM unnest('{2,NULL,4}'::int[]) AS i;
3)SELECT i FROM (SELECT unnest('{3,NULL,4}'::int[])) AS t(i);
所有这些都在预期的结果中包含NULL
行
i
---
1
(null)
4
要将数组元素转换为其他类型,可以在展开数组后将元素转换为基本类型,或者转换数组< / em>在扩展之前自己使用不同的数组类型。对我来说,第一个变体似乎更简单,更短:
A)SELECT unnest('{4,NULL,1}'::int[])::text;
B)SELECT unnest('{4,NULL,2}'::int[]::text[]);
i
---
4
(null)
1
2A)
由于某种原因,我无法将2)
与A)
SELECT * FROM unnest('{2,NULL,1}'::int[])::text;
错误:“::”
处或附近的语法错误
我可以接受。一个罕见的角落案例,由于某种原因尚未实施 然而,所有其他组合都飞了:
1A)SELECT unnest('{1,NULL,1}'::int[])::text AS i;
2A) SELECT i FROM unnest('{2,NULL,1}'::int[])::text AS i;
3A)SELECT i FROM (SELECT unnest('{3,NULL,1}'::int[])::text) AS t(i);
1B)SELECT unnest('{1,NULL,2}'::int[]::text[]) AS i;
2B)SELECT i FROM unnest('{2,NULL,2}'::int[]::text[]) AS i;
3B)SELECT i FROM (SELECT unnest('{3,NULL,2}'::int[]::text[])) AS t(i);
与上述结果相同。
以下观察仅涉及A)
。用B)
替换可以避免这个问题。
正如预期的那样,我们已经看到数组中的NULL
元素导致到目前为止在所有查询中都有一个NULL
值的行。但是,将某些数组类型的结果转换为某些基类型时,情况并非如此。
此处 NULL值的行突然消失(!):
SELECT unnest('{1,NULL,4}'::int[])::int8;
i
---
1
4
我去看了兔子洞的深度。以下是一些例子:
NULL
消失了:
SELECT unnest('{1,NULL,1}'::int[])::int2;
SELECT unnest('{1,NULL,2}'::int[])::int8;
SELECT unnest('{1,NULL,3}'::int[])::real;
SELECT unnest('{1,NULL,4}'::int[])::float8;
SELECT unnest('{1,NULL,5}'::int[])::numeric;
SELECT unnest('{1,NULL,6}'::numeric[])::int2;
SELECT unnest('{1,NULL,7}'::numeric[])::int8;
SELECT unnest('{1,NULL,8}'::numeric[])::real;
SELECT unnest('{1,NULL,9}'::numeric[])::float8;
SELECT unnest('{1,NULL,a}'::text[])::char;
SELECT unnest('{1,NULL,b}'::text[])::char(1);
SELECT unnest('{1,NULL,c}'::text[])::varchar(10); -- !!!
SELECT unnest('{1,NULL,d}'::varchar[])::varchar(10); -- !!!
SELECT unnest('{2013-1-1,NULL,2013-1-1}'::date[])::timestamp;
SELECT unnest('{2013-1-1,NULL,2013-1-1}'::timestamp[])::date;
SELECT unnest('{23:11,NULL,23:11}'::time[])::interval;
SELECT unnest('{23:11,NULL,23:11}'::interval[])::time;
NULL
留下来:
SELECT unnest('{1,NULL,1}'::int[])::int4; -- is really from int to int
SELECT unnest('{1,NULL,2}'::int[])::text;
SELECT unnest('{1,NULL,3}'::int8[])::text;
SELECT unnest('{1,NULL,4}'::numeric[])::text;
SELECT unnest('{1,NULL,5}'::text[])::int;
SELECT unnest('{1,NULL,6}'::text[])::int8;
SELECT unnest('{1,NULL,7}'::text[])::numeric;
SELECT unnest('{1,NULL,8}'::text[])::varchar; -- !!!
SELECT unnest('{1,NULL,9}'::varchar[])::text; -- !!!
SELECT unnest('{2013-1-1,NULL,2013-1-1}'::date[])::text;
SELECT unnest('{2013-1-1,NULL,2013-1-1}'::text[])::date;
SELECT unnest('{23:11,NULL,23:11}'::time[])::text;
SELECT unnest('{23:11,NULL,23:11}'::text[])::time;
这似乎是不可接受的。
在测试了很多组合后,模式似乎是:
在相关类型之间转换会导致NULL
元素丢失
在不相关的类型之间进行转换会导致保留NULL
个元素
除了varchar[]
- &gt; text
反之亦然,这破坏了我的这个小假设。或者varchar
和text
的差异比我想象的要大。
使用PostgreSQL 9.1和9.2进行测试。相同的结果。
-> SQLfiddle
我在这里遗漏了什么吗?有人可以解释这种行为吗? 如果没有,问题就变成了:我应该在文件中提交错误报告吗?
答案 0 :(得分:2)
不支持转换SRF函数(在FROM子句中) - 您不能在那里使用任何运算符。只允许函数调用。
只能在列列表中进行强制转换:
postgres=# SELECT * FROM unnest('{2,NULL,1}'::int[])::text;
ERROR: syntax error at or near "::"
LINE 1: SELECT * FROM unnest('{2,NULL,1}'::int[])::text;
^
postgres=# SELECT v::text FROM unnest('{2,NULL,1}'::int[]) g(v);
v
────────
2
[null]
1
(3 rows)
从NULL中丢失行可能是错误,应报告
postgres=# SELECT unnest('{1,NULL,4}'::int[])::text;
unnest
────────
1
[null]
4
(3 rows)
postgres=# SELECT unnest('{1,NULL,4}'::int[])::numeric;
unnest
────────
1
4
(2 rows)
没有理由,为什么应该删除NULL行,我想