Det här svaret kan vara lite klurigt...
Oracle är mycket kräsen med inställda operationer. Varje kolumn måste ha samma datatyp som motsvarande i den andra, tredje osv. frågan.
Jag tror din andra fråga misslyckas eftersom Oracle utvärderar to_number()
som ett nummer före för att utföra unionen
men utvärderar det för "null-ness" efter . Din första fråga lyckas eftersom det första värdet har utvärderats för "null-ness" och sedan union
inträffar. Detta innebär att utvärderingsordningen är:
- Första valda funktioner
- Första val av datatyper
- Andra valfunktioner
- fackförening
- Andra val av datatyper
Jag ska försöka bevisa detta steg för steg, men jag är inte säker på att det kommer att vara ett absolut bevis.
Båda följande frågor
select 1 from dual union select '1' from dual;
select '1' from dual union select 1 from dual;
kommer att misslyckas med följande fel eftersom ingen implicit konvertering äger rum.
Men båda följande kommer att lyckas
select null from dual union select '1' from dual;
select null from dual union select 1 from dual;
Om vi väljer dump av dessa två frågor returneras följande:
SQL> select dump(a)
2 from ( select null a from dual union select '1' from dual );
DUMP(A)
-------------------------------------------------------------------
Typ=96 Len=1: 49
NULL
SQL> select dump(a)
2 from ( select null a from dual union select 1 from dual );
DUMP(A)
-------------------------------------------------------------------
Typ=2 Len=2: 193,2
NULL
Som du kan se har kolumnerna olika datatyper
. Den första frågan, med ett tecken, returnerar ett char
och den andra returnerar ett nummer, men ordningen har vänts, med den andra select
kommer först.
Slutligen, om vi tittar på dump
av din första fråga
SQL> select substr(dump(ename),1,35) a, substr(dump(loc),1,35) b
2 from ( select ename,to_number(null) as loc from emp
3 union
4 select to_char(null),loc from dept
5 );
A B
----------------------------------- -----------------------------------
Typ=1 Len=6: 104,97,104,97,104,97 NULL
NULL Typ=1 Len=6: 104,97,104,97,104,97
SQL>
Du kan se den dump(to_number(null))
är inget; men en varchar2
inte en char
returneras, eftersom detta är datatypen för din kolumn. Det är intressant att notera att ordningen på de returnerade satserna inte har omvänts och att om du skulle skapa den här frågan som en tabell skulle båda kolumnerna vara en varchar2
.
När du bestämmer datatypen för en kolumn i en urvalsfråga tar Oracle den första kända datatypen och använder den sedan för att beräkna den övergripande datatypen. Det skulle vara anledningen till att frågorna var den första välj
var null hade sina rader omvända.
Din första fråga lyckas eftersom den första valen, välj ename,to_number(null) från emp
, "beskriver" hur resultatuppsättningen kommer att se ut. |varchar2|null|
. Den andra frågan lägger sedan till |varchar2|varchar2|
, vilket inte orsakar några problem.
Din andra fråga misslyckas eftersom den första väljer välj ename,to_number(null) från emp
"beskriver" resultatuppsättningen som varchar2, null
. Men du försöker sedan lägga till ett nullnummer och en varchar2 i unionen
.
Trosprånget här är att Oracle bestämmer att to_number(null)
är ett nummer före till unionen
och inte utvärdera det för "nullhet" förrän efter. Jag vet inte riktigt hur man testar om detta verkligen händer eftersom du inte kan skapa ett objekt med en null
kolumn och som du noterar kan du inte välja den heller.
Eftersom jag inte kan bevisa något som Oracle inte tillåter ska jag försöka hitta empiriska bevis. Tänk på resultaten (eller felen) av följande frågor.
SQL> select 1 as a from dual union select to_number(null) from dual;
A
----------
1
SQL> select '1' as a from dual union select to_number(null) from dual;
select '1' as a from dual union select to_number(null) from dual
*
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression
SQL> select 1 as a from dual union select to_char(null) from dual;
select 1 as a from dual union select to_char(null) from dual
*
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression
SQL> select '1' as a from dual union select to_char(null) from dual;
A
-
1
De verkar visa att to_char
och to_number
, oavsett om de utförs på en noll definierar implicit en datatyp som sedan utvärderas för dess lämplighet i en union
, innan de bedöms för "null-ness"
Den här förklaringen skulle också täcka sammansmält
problemet som to_number(null)
är ett nummer före det är en noll.