Този отговор може да е малко неразбираем...
Oracle е много придирчив към множество операции. Всяка колона трябва да има същия тип данни като съответните във втората, третата и т.н. заявки.
Аз мисля втората ви заявка е неуспешна, защото Oracle оценява to_number()
като номер преди за извършване на union
но го оценява за "нулевост" след . Първата ви заявка е успешна, защото първата стойност е оценена за „нулевост“ и след това union
възниква. Това означава, че редът на оценяване е:
- Първи избрани функции
- Първи избор на типове данни
- Втори избор на функции
- съюз
- Втори избран тип данни
Ще се опитам да докажа това стъпка по стъпка, но не съм сигурен, че ще бъде абсолютно доказателство.
И двете следните заявки
select 1 from dual union select '1' from dual;
select '1' from dual union select 1 from dual;
ще се провали със следната грешка, тъй като не се извършва имплицитно преобразуване.
И двете обаче ще успеят
select null from dual union select '1' from dual;
select null from dual union select 1 from dual;
Ако изберем dump
от тези две заявки се връща следното:
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
Както можете да видите, колоните имат различни типове данни
. Първата заявка, със знак, връща char
и вторият връща число, но редът е обърнат, с втория select
на първо място.
И накрая, ако разгледаме dump
от първото ви запитване
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>
Можете да видите този dump(to_number(null))
е нула; но varchar2
не е char
се връща, защото това е типът данни на вашата колона. Интересно е да се отбележи, че редът на върнатите изрази не е обърнат и че ако създадете тази заявка като таблица, и двете колони ще бъдат varchar2
.
Когато определя типа данни на колона в заявка за избор, Oracle взема първия известен тип данни и след това го използва, за да изчисли общия тип данни. Това би било причината заявките, при които първият select
беше нула, ако редовете им бяха обърнати.
Първата ви заявка е успешна, защото първото изберете, select ename,to_number(null) from emp
, "описва" как ще изглежда наборът от резултати. |varchar2|null|
. След това втората заявка добавя |varchar2|varchar2|
, което не създава проблеми.
Втората ви заявка е неуспешна, защото първата изберете select ename,to_number(null) from emp
"описва" резултатния набор като varchar2, null
. След това обаче се опитвате да добавите нулево число и varchar2 в union
.
Скокът на вярата тук е, че Oracle решава, че to_number(null)
е число преди към union
и не го оценява за "нулевост" до след това. Наистина не знам как да тествам дали това наистина се случва, тъй като не можете да създадете обект с null
и както забелязахте, вие също не можете да го изберете.
Тъй като не мога да докажа нещо, което Oracle забранява, ще опитам за емпирични доказателства. Обмислете резултатите (или грешките) от следните заявки.
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
Те изглежда демонстрират, че to_char
и to_number
, без значение дали се изпълняват върху null имплицитно дефинират тип данни, който след това се оценява за неговата пригодност в union
, преди оценката им за „нулевост“
Това обяснение ще обхване и coalesce
проблем като to_number(null)
е число преди това е нула.