Đầu tiên một chút lý thuyết:Null (SQL)
Các phần quan trọng nhất đối với chúng tôi từ liên kết trên:
So sánh với NULL và logic ba giá trị (3VL)
Vì Null không phải là thành viên của bất kỳ miền dữ liệu nào, nên nó không được coi là "giá trị", mà là một điểm đánh dấu (hoặc trình giữ chỗ) cho biết sự vắng mặt của giá trị. Do đó, các phép so sánh với Null không bao giờ có thể dẫn đến Đúng hoặc Sai, mà luôn dẫn đến kết quả logic thứ ba, Không xác định. [8] Kết quả logic của biểu thức dưới đây, so sánh giá trị 10 với Null, là Không xác định:
SELECT 10 = NULL -- Results in Unknown
để cả hai so sánh:x = NULL
và x <> NULL
đánh giá là NULL (không xác định).
SQL thực thi ba kết quả logic, vì vậy việc triển khai SQL phải cung cấp cho một logic ba giá trị chuyên biệt (3VL). Các quy tắc chuyển đổi logic ba giá trị của SQL được hiển thị trong bảng bên dưới (p vàq đại diện cho các trạng thái logic) "[9] Các bảng sự thật mà SQL sử dụng cho AND, OR và NOT tương ứng với một đoạn chung của logic có giá trị Kleene và Łukasiewiczthree ( khác nhau trong định nghĩa của chúng về hàm ý, tuy nhiên SQL định nghĩa không có hoạt động nào như vậy).
+---------+-------------+-------------+-------------+-----------+--------+ | p | q | p OR q | p AND q | p = q |p != q | +---------+-------------+-------------+-------------+-----------+--------+ | True | True | True | True | True | False | | True | False | True | False | False | True | | True | Unknown | True | Unknown | Unknown | Unknown| | False | True | True | False | False | True | | False | False | False | False | True | False | | False | Unknown | Unknown | False | Unknown | Unknown| | Unknown | True | True | Unknown | Unknown | Unknown| | Unknown | False | Unknown | False | Unknown | Unknown| | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown| +---------+-------------+-------------+-------------+-----------+--------+
Ảnh hưởng của Không xác định trong mệnh đề WHERE
Logic ba giá trị của SQL gặp phải trong Ngôn ngữ thao tác dữ liệu (DML) trong các vị từ so sánh của các câu lệnh và truy vấn DML. Mệnh đề TheWHERE khiến câu lệnh DML chỉ hoạt động trên các hàng đó mà vị từ đánh giá là True.
Tóm lại:Mệnh đề WHERE coi NULL là FALSE
Bây giờ hãy xem xét một trường hợp đơn giản hơn:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
và một truy vấn:
SELECT * FROM t1 WHERE x IN (1, NULL);
Truy vấn trên là một đường tắt dẫn đến truy vấn này:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
Đối với hàng thứ hai từ bảng t
(x =NULL) điều kiện này giống như sau:
WHERE NULL = 1
OR NULL = NULL
vì vậy điều kiện này cho hàng x = NULL
đánh giá là NULL vì NULL=1
là NULL, NULL=NULL
là NULL và NULL OR NULL
cũng là NULL (vui lòng xem bảng 3VL ở trên).
Bây giờ hãy xem xét trường hợp tò mò hơn:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Mệnh đề này x NOT IN (1, NULL)
tương đương với NOT ( x IN (1, NULL) )
vì vậy nó cũng tương đương với:
NOT (
x = 1
OR
x = NULL
)
và theo luật của De Morgan, nó tương đương với:
NOT ( x = 1 ) AND NOT ( x = NULL )
và (nếu chúng ta thay thế NOT x = y
với x <> y
) nó cũng tương đương với:
x <> 1 AND x <> NULL
Vui lòng xem kỹ điều kiện cuối cùng:
WHERE
x <> 1 AND x <> NULL
Chúng tôi biết nhiều hơn x <> NULL
luôn đánh giá là NULL. Chúng tôi cũng biết từ bảng 3VL ở trên, rằng cả true AND NULL
là NULL và false AND NULL
đánh giá là FALSE, do đó, toàn bộ điều kiện luôn đánh giá là FALSE hoặc NULL, nhưng nó không bao giờ đánh giá là TRUE.
Do đó, một truy vấn với điều kiện này:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
luôn trả về tập kết quả trống
Và bây giờ là truy vấn của bạn, cũng rất tò mò:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
có thể được viết lại (sử dụng các giá trị không đổi) thành:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Truy vấn này đang sử dụng cái gọi là biểu thức giá trị hàng
Về cơ bản là một điều kiện sử dụng giá trị hàng expressin như thế này
(a, b) = (x, y)
tương đương với cái này:
a = x AND b = y
vì vậy truy vấn trên có thể được viết lại thành sau:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
Theo luật của De Morgan, điều này giống với:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
và xa hơn nữa là:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Kể từ phần đầu tiên ( id <> 1 OR val <> NULL )
của điều kiện được đánh giá là true chỉ trong trường hợp id <> 1
(vui lòng xem bảng 3VL ở trên), điều kiện này có thể được đơn giản hóa thành:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
và xa hơn nữa (theo luật của De Morgan) thành:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
vì vậy không phải (1,1)
cũng không phải (2,2)
từ nguồn data1
tuân thủ các điều kiện này.