unnest()
的非常奇怪的行为.
介绍
使用unnest()有三种基本语法变体:
1)SELECT unnest(‘{1,NULL,4}’:: int [])AS i;
2)SELECT i FROM unnest(‘{2,4}’:: int [])AS i;
3)SELECT i FROM(SELECT unnest(‘{3,4}’:: int []))AS t(i);
所有这些都包含一个在结果中按预期方式为NULL的行
i --- 1 (null) 4
要将数组元素转换为其他类型,可以在扩展数组后立即将元素转换为基本类型,或者在展开之前将数组本身转换为其他数组类型.第一个变体对我来说似乎有点简单和简短:
A)SELECT unnest(‘{4,1}’:: int []):: text;
B)SELECT unnest(‘{4,2}’:: int [] :: text []);
i --- 4 (null) 1
奇怪的行为
可能的所有组合除2A)
由于某种原因,不能将2)与A)结合起来
SELECT * FROM unnest('{2,1}'::int[])::text;
ERROR: Syntax error at or near “::”
我可以接受.一个罕见的角落案例,由于某种原因尚未实施.
然而,所有其他组合飞行:
1A)SELECT unnest(‘{1,1}’:: int []):: text AS i;
2A)SELECT i FROM unnest(‘{2,1}’:: int []):: text AS i;
3A)SELECT i FROM(SELECT unnest(‘{3,1}’:: int []):: text)AS t(i);
1B)SELECT unnest(‘{1,2}’:: int [] :: text [])AS i;
2B)SELECT i FROM unnest(‘{2,2}’:: int [] :: text [])AS i;
3B)SELECT i FROM(SELECT unnest(‘{3,2}’:: int [] :: text []))AS t(i);
与上述结果相同.
真奇怪的行为
以下观察仅涉及A).用B)代替可以避免这个问题.
正如预期的那样,我们已经看到数组中的NULL元素导致到目前为止在所有查询中都有一个具有NULL值的行.但是,将某些数组类型的结果转换为某些基类型时,情况并非如此.
这里具有NULL值的行突然消失(!):
SELECT unnest('{1,4}'::int[])::int8; i --- 1 4
例子
我去看兔子洞有多深.这里有些例子:
NULL消失:
SELECT unnest('{1,1}'::int[])::int2; SELECT unnest('{1,2}'::int[])::int8; SELECT unnest('{1,3}'::int[])::real; SELECT unnest('{1,4}'::int[])::float8; SELECT unnest('{1,5}'::int[])::numeric; SELECT unnest('{1,6}'::numeric[])::int2; SELECT unnest('{1,7}'::numeric[])::int8; SELECT unnest('{1,8}'::numeric[])::real; SELECT unnest('{1,9}'::numeric[])::float8; SELECT unnest('{1,a}'::text[])::char; SELECT unnest('{1,b}'::text[])::char(1); SELECT unnest('{1,c}'::text[])::varchar(10); -- !!! SELECT unnest('{1,d}'::varchar[])::varchar(10); -- !!! SELECT unnest('{2013-1-1,2013-1-1}'::date[])::timestamp; SELECT unnest('{2013-1-1,2013-1-1}'::timestamp[])::date; SELECT unnest('{23:11,23:11}'::time[])::interval; SELECT unnest('{23:11,23:11}'::interval[])::time;
NULL保持:
SELECT unnest('{1,1}'::int[])::int4; -- is really from int to int SELECT unnest('{1,2}'::int[])::text; SELECT unnest('{1,3}'::int8[])::text; SELECT unnest('{1,4}'::numeric[])::text; SELECT unnest('{1,5}'::text[])::int; SELECT unnest('{1,6}'::text[])::int8; SELECT unnest('{1,7}'::text[])::numeric; SELECT unnest('{1,8}'::text[])::varchar; -- !!! SELECT unnest('{1,9}'::varchar[])::text; -- !!! SELECT unnest('{2013-1-1,2013-1-1}'::date[])::text; SELECT unnest('{2013-1-1,2013-1-1}'::text[])::date; SELECT unnest('{23:11,23:11}'::time[])::text; SELECT unnest('{23:11,23:11}'::text[])::time;
这似乎是不可接受的.
在测试了很多组合后,模式似乎是:
在相关类型之间转换会导致NULL元素丢失.
在不相关的类型之间转换会导致保留NULL元素.
除了varchar [] – >文本,反之亦然,破坏了我的这个小假设.或varchar和文本的差异比我想象的要多.
使用Postgresql 9.1和9.2进行测试.相同的结果.
-> SQLfiddle
问题
解决方法
只能在列列表中进行强制转换:
postgres=# SELECT * FROM unnest('{2,1}'::int[])::text; ERROR: Syntax error at or near "::" LINE 1: SELECT * FROM unnest('{2,1}'::int[])::text; ^ postgres=# SELECT v::text FROM unnest('{2,1}'::int[]) g(v); v ──────── 2 [null] 1 (3 rows)
从NULL中丢失的行可能是错误,应该报告
postgres=# SELECT unnest('{1,4}'::int[])::text; unnest ──────── 1 [null] 4 (3 rows) postgres=# SELECT unnest('{1,4}'::int[])::numeric; unnest ──────── 1 4 (2 rows)
我认为没有理由,为什么应该删除NULL行
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。