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
要将数组元素转换为不同的类型,可以在扩展数组后立即将元素转换为基本类型,或者在扩展之前将数组本身转换为不同的数组类型。第一个变体对我来说似乎更简单更短:
甲)SELECT unnest('{4,NULL,1}'::int[])::text;
乙)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[]
->text
反之亦然,这破坏了我的这个小假设。或者varchar
和text
我想象的不同。
使用 PostgreSQL 9.1 和 9.2 测试。相同的结果。
-> SQL小提琴
问题
我在这里错过了什么吗?有人可以解释这种行为吗?
如果没有,问题就变成了:我应该继续提交错误报告吗?