Nhà điều hành
Đây là tòa nhà trên nhà điều hành thông minh của @ Daniel .
Trong khi ở đó, tạo tổ hợp hàm / toán tử bằng cách sử dụng các loại đa hình . Sau đó, nó hoạt động cho bất kỳ loại - giống như các cấu trúc.
Và làm cho các chức năng IMMUTABLE
.
CREATE FUNCTION is_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS DISTINCT FROM $2';
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
);
Một tìm kiếm nhanh với biểu tượng xuất hiện trống rỗng, do đó toán tử <!>
dường như không được sử dụng trong bất kỳ mô-đun nào.
Nếu bạn sẽ sử dụng toán tử này rất nhiều, bạn có thể bổ sung thêm một số thứ khác để hỗ trợ trình hoạch định truy vấn ( như bị mất đề xuất trong một bình luận ). Để bắt đầu, bạn có thể thêm COMMUTATOR
và NEGATOR
các mệnh đề để hỗ trợ trình tối ưu hóa truy vấn. Thay thế CREATE OPERATOR
từ trên bằng cái này:
CREATE OPERATOR <!> (
PROCEDURE = is_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = <!>
, NEGATOR = =!=
);
Và thêm:
CREATE FUNCTION is_not_distinct_from(anyelement, anyelement)
RETURNS bool LANGUAGE sql IMMUTABLE AS
'SELECT $1 IS NOT DISTINCT FROM $2';
CREATE OPERATOR =!= (
PROCEDURE = is_not_distinct_from(anyelement,anyelement),
LEFTARG = anyelement
, RIGHTARG = anyelement
, COMMUTATOR = =!=
, NEGATOR = <!>
);
Nhưng các điều khoản bổ sung sẽ không giúp ích cho trường hợp sử dụng và các chỉ mục đơn giản vẫn sẽ không được sử dụng. Nó phức tạp hơn nhiều để đạt được điều đó. (Tôi chưa thử.) Đọc chương "Thông tin tối ưu hóa toán tử" trong hướng dẫn để biết chi tiết.
Trường hợp thử nghiệm
Trường hợp thử nghiệm trong câu hỏi chỉ có thể thành công nếu tất cả các giá trị trong mảng giống hệt nhau. Đối với mảng trong câu hỏi ( '{null,A}'::text[]
) kết quả luôn luôn ĐÚNG. Đó có phải là dự định? Tôi đã thêm một bài kiểm tra khác cho "IS DISTINCT TỪ TẤT CẢ":
SELECT foo
, foo <!> ANY ('{null,A}'::text[]) AS chk_any
, foo <!> ALL ('{null,A}'::text[]) AS chk_all
FROM (
VALUES ('A'),('Z'),(NULL)
) z(foo)
foo | chk_any | chk_all
-----+---------+---------
A | t | f
Z | t | t
| t | f
Thay thế với các nhà khai thác tiêu chuẩn
foo IS DISTINCT FROM ANY (test_arr) -- illegal syntax
gần như có thể được dịch sang
foo = ALL (test_arr) IS NOT TRUE
foo = ALL (test_arr)
mang lại ...
TRUE
.. nếu tất cả các phần tử là foo
FALSE
.. nếu bất kỳ NOT NULL
phần tử nào là <> foo
NULL
.. nếu ít nhất một phần tử IS NULL
và không có phần tử nào là<> foo
Vì vậy, trường hợp góc còn lại là nơi
- foo IS NULL
- và test_arr
không có gì ngoài NULL
các phần tử.
Nếu một trong hai có thể được loại trừ, chúng tôi đã hoàn thành. Do đó, sử dụng thử nghiệm đơn giản nếu
- cột được xác định NOT NULL
.
- hoặc bạn biết mảng không bao giờ là tất cả NULL.
Khác, kiểm tra bổ sung:
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
Ở đâu 'A'
và 'B'
có thể là bất kỳ giá trị riêng biệt. Giải thích và giải pháp thay thế theo câu hỏi liên quan này trên SO:
Là mảng tất cả các NULL trong PostgreQuery
Một lần nữa, nếu bạn biết về bất kỳ giá trị nào không thể tồn tại test_arr
, ví dụ chuỗi rỗng ''
, bạn vẫn có thể đơn giản hóa:
AND ('' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL)
Dưới đây là một ma trận thử nghiệm hoàn chỉnh để kiểm tra tất cả các kết hợp:
SELECT foo, test_arr
, foo = ALL(test_arr) IS NOT TRUE AS test_simple
, foo = ALL(test_arr) IS NOT TRUE
AND ('A' = ALL(test_arr) IS NOT NULL OR
'B' = ALL(test_arr) IS NOT NULL OR
foo IS NOT NULL) AS test_sure
FROM (
VALUES ('A'),('Z'),(NULL)
) v(foo)
CROSS JOIN (
VALUES ('{null,A}'::text[]),('{A,A}'),('{null,null}')
) t(test_arr)
foo | test_arr | test_simple | test_sure
-----+-------------+-------------+-----------
A | {NULL,A} | t | t
A | {A,A} | f | f -- only TRUE case
A | {NULL,NULL} | t | t
Z | {NULL,A} | t | t
Z | {A,A} | t | t
Z | {NULL,NULL} | t | t
| {NULL,A} | t | t
| {A,A} | t | t
| {NULL,NULL} | t | f -- special case
Đây là một chút dài dòng hơn so với giải pháp của AndroidEXCEPT
, nhưng về cơ bản là nhanh hơn.