NULL emements铸造UNNEST的结果时,会丢失()(NULL emements lost

2019-09-02 08:32发布

我偶然发现了非常奇怪的行为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

铸数组元素到一个不同类型,可以扩大后阵右铸元件为基本类型,或者扩大之前 数组本身转换为不同的阵列型。 第一个变种似乎稍微简单和更短的对我说:

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[] - > text ,反之亦然象垃圾一样清除我的这个小假说。 或varchartext不同,比我想象的更多。

测试了PostgreSQL的9.1和9.2。 相同的结果。
- > SQLfiddle

问题

我失去了一些东西在这里? 有人可以解释这种现象?
如果不是这样,问题就变成了:我应该先走的文件中的错误报告?

Answer 1:

铸造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 emements lost when casting result of unnest()