Câu trả lời này có thể hơi lan man ...
Oracle là rất cầu kỳ với các hoạt động thiết lập. Mỗi cột phải có cùng kiểu dữ liệu với các cột tương ứng trong các truy vấn thứ hai, thứ ba, v.v..
Tôi nghĩ rằng truy vấn thứ hai của bạn không thành công vì Oracle đánh giá to_number()
như một số trước để thực hiện union
nhưng đánh giá nó là "null-ness" after . Truy vấn đầu tiên của bạn thành công vì giá trị đầu tiên đã được đánh giá cho "null-ness" và sau đó là union
xảy ra. Điều này ngụ ý rằng thứ tự đánh giá là:
- Các chức năng được lựa chọn đầu tiên
- Loại dữ liệu được chọn đầu tiên
- Chức năng lựa chọn thứ hai
- công đoàn
- Loại dữ liệu được lựa chọn thứ hai
Tôi sẽ cố gắng chứng minh điều này từng bước nhưng tôi không chắc nó sẽ trở thành bằng chứng tuyệt đối.
Cả hai truy vấn sau đây
select 1 from dual union select '1' from dual;
select '1' from dual union select 1 from dual;
sẽ không thành công với lỗi sau vì không có chuyển đổi ngầm định nào diễn ra.
Tuy nhiên, cả hai cách sau sẽ thành công
select null from dual union select '1' from dual;
select null from dual union select 1 from dual;
Nếu chúng tôi chọn dump
trong số hai truy vấn này, kết quả sau sẽ được trả về:
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
Như bạn có thể thấy, các cột có kiểu dữ liệu khác nhau
. Truy vấn đầu tiên, với một ký tự, trả về một char
và thứ hai trả về một số, nhưng thứ tự đã được xoay chuyển, với select
thứ hai đến trước.
Cuối cùng, nếu chúng ta xem xét dump
truy vấn đầu tiên của bạn
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>
Bạn có thể thấy rằng dump(to_number(null))
là null; nhưng một varchar2
không phải là char
đang được trả về, vì đây là kiểu dữ liệu của cột của bạn. Thật thú vị khi lưu ý rằng thứ tự của các câu lệnh trả về không bị đảo ngược và nếu bạn tạo truy vấn này dưới dạng bảng thì cả hai cột sẽ là varchar2
.
Khi quyết định kiểu dữ liệu của một cột trong một truy vấn chọn, Oracle sẽ lấy kiểu dữ liệu đã biết đầu tiên và sau đó sử dụng kiểu dữ liệu đó để tính toán kiểu dữ liệu tổng thể. Đây sẽ là lý do tại sao các truy vấn trong đó select
đầu tiên là null khi các hàng của họ bị đảo ngược.
Truy vấn đầu tiên của bạn thành công vì lần chọn đầu tiên, select ename,to_number(null) from emp
, "mô tả" tập kết quả sẽ trông như thế nào. |varchar2|null|
. Sau đó, truy vấn thứ hai thêm, |varchar2|varchar2|
, không gây ra vấn đề gì.
Truy vấn thứ hai của bạn không thành công vì lần chọn đầu tiên select ename,to_number(null) from emp
"mô tả" kết quả được đặt là varchar2, null
. Tuy nhiên, sau đó bạn cố gắng thêm một số null và một varchar2 trong union
.
Bước nhảy vọt của niềm tin ở đây là Oracle đang quyết định rằng to_number(null)
là một số trước tới union
và không đánh giá nó cho "null-ness" cho đến sau đó. Tôi thực sự không biết cách kiểm tra xem điều này có thực sự xảy ra hay không vì bạn không thể tạo một đối tượng có null
và như bạn lưu ý, bạn cũng không thể chọn nó.
Vì tôi không thể chứng minh điều gì đó mà Oracle không cho phép, tôi sẽ cố gắng tìm bằng chứng thực nghiệm. Xem xét kết quả (hoặc lỗi) của các truy vấn sau.
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
Chúng dường như chứng minh rằng to_char
và to_number
, cho dù chúng được thực hiện trên null hay không, xác định ngầm một kiểu dữ liệu mà sau đó sẽ được đánh giá về tính phù hợp của nó trong một union
, trước khi họ đánh giá "null-ness"
Giải thích này cũng sẽ bao gồm coalesce
vấn đề dưới dạng to_number(null)
là một số trước nó là một null.