[英]Postgres SQL Exclusive OR (XOR) CHECK CONSTRAINT, is it possible?
是否可以進行 XOR CHECK 約束?
我正在我剛剛制作的名為test的測試表上執行此操作,該表有 3 列:
我為此做了一個檢查約束:
(a IS NOT NULL AND b = NULL) OR (b IS NOT NULL AND a = NULL)
我通過這樣做來測試它:
INSERT INTO public.test(
id, a, b)
VALUES (1, 1, 1);
哪個應該失敗,因為它在 OR 的任一側都沒有評估為 TRUE。 但是,它插入得很好。
當我查看 postgres 實際存儲為約束的內容時,我得到了這個:
(a IS NOT NULL AND b = NULL::bigint OR b IS NOT NULL AND a = NULL::bigint)
我聽說 AND 優先於 OR 所以即使這仍然有效。
有人對此有解決方案嗎? 最好是三列或更多列也可以的? 我知道這些可能會更復雜。
編輯:改變
= NULL
至
IS NULL
給我嗎:
ERROR: cannot cast type boolean to bigint
對,正如@a_horse_with_no_name 所指出的那樣, a = NULL
和b = NULL
位是問題所在。 您也可以考慮這種不需要OR
運算符的導數:
create table test
(
id integer primary key,
a integer,
b integer,
check ((a IS NULL) != (b IS NULL))
);
當然,這僅適用於僅兩列XOR
比較。 在類似的測試表中通過三列或更多列的XOR
比較,您可以采用更像這樣的類似方法:
create table test
(
id integer primary key,
a integer,
b integer,
c integer,
check ((a IS NOT NULL)::INTEGER +
(b IS NOT NULL)::INTEGER +
(c IS NOT NULL)::INTEGER = 1)
);
您不能將 NULL 值與=
進行比較,您需要IS NULL
(a IS NOT NULL AND b is NULL) OR (b IS NOT NULL AND a is NULL)
對於檢查約束,您需要將整個表達式括在括號中:
create table xor_test
(
id integer primary key,
a integer,
b integer,
check ((a IS NOT NULL AND b is NULL) OR (b IS NOT NULL AND a is NULL))
);
-- works
INSERT INTO xor_test(id, a, b) VALUES (1, null, 1);
-- works
INSERT INTO xor_test(id, a, b) VALUES (2, 1, null);
-- fails
INSERT INTO xor_test(id, a, b) VALUES (3, 1, 1);
或者,檢查約束可以簡化為
check ( num_nonnulls(a,b) = 1 )
這也更容易適應更多列
這是明確的異或。 為什么不先將其定義為布爾運算符? 它也可能對其他情況有用。
CREATE OR REPLACE FUNCTION public.xor (a boolean, b boolean) returns boolean immutable language sql AS
$$
SELECT (a and not b) or (b and not a);
$$;
CREATE OPERATOR #
(
PROCEDURE = public.xor,
LEFTARG = boolean,
RIGHTARG = boolean
);
然后 CHECK ((a IS NULL) # (b IS NULL))
感謝維克。 我在vue中進行了類似的測試。 在左連接中,至少 2 列或更多列不能為空。
SELECT
(tbl1.col1 IS NOT NULL)::INTEGER +
(tbl2.col1 IS NOT NULL)::INTEGER +
(tbl3.col1 IS NOT NULL)::INTEGER +
(tbl4.col1 IS NOT NULL)::INTEGER +
(tbl5.col1 IS NOT NULL)::INTEGER +
(tbl6.col1 IS NOT NULL)::INTEGER > 1 AS
b_mult_cols
FROM tlb1
LEFT JOIN tbl2 ON tlb1.col1 = tlb2.col1
LEFT JOIN tbl3 ON tlb1.col1 = tlb3.col1
LEFT JOIN tbl4 ON tlb1.col1 = tlb4.col1
LEFT JOIN tbl5 ON tlb1.col1 = tlb5.col1
LEFT JOIN tbl6 ON tlb1.col1 = tlb6.col1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.