2013-05-09 53 views
4

當我在展開數組之後進行強制轉換時,我偶然發現了一個非常奇怪的行爲unnest()當uncast拋出結果時丟失NULL emements()

介紹

有三種基本的語法變種使用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行在預期的結果

要投射的數組元素爲不同的類型,可以右擴大陣列後鑄元件爲基本型,或擴大之前陣列本身轉換爲不同的陣列型。第一個變種似乎稍微簡單和更短的對我說:

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; 

ERROR: syntax error at or near "::"

我可以接受。一個罕見的角落案件,由於某種原因尚未實施。
所有其他組合飛,雖然:

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

問題

我失去了一些東西在這裏?有人可以解釋這種行爲嗎?
如果沒有,問題就變成了:我應該在文件中提交一個錯誤報告嗎?

回答

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) 

沒有理由,爲什麼空行應該被丟棄,我認爲

+0

謝謝,帕維爾。我將提交第二部分的錯誤報告。 – 2013-05-09 22:42:46

+1

[我報告了錯誤,Tom Lane立即發現並解決了這個問題](http://www.postgresql.org/message-id/flat/[email protected]#E1Ub8p6-0006NC-Ja @ wrigleys.postgresql.org)。 Postgres 9.3不會出現這個錯誤,但他們沒有反補丁,所以不會破壞舊代碼。 – 2013-05-14 21:20:29

相關問題