变体1
由于您所需的只是带有的单列standard = true
,因此在所有其他行中将standard设置为NULL。然后一个普通的UNIQUE
约束起作用,因为NULL值不违反它:
CREATE TABLE taxrate (
taxrate int PRIMARY KEY
, standard bool DEFAULT true
, CONSTRAINT standard_true_or_null CHECK (standard) -- yes, that's the whole constraint
, CONSTRAINT standard_only_1_true UNIQUE (standard)
);
DEFAULT
是一个可选的提醒,输入的第一行应成为默认行。它没有强制执行任何操作。虽然您不能将设置多行standard = true
,但仍然可以将所有行设置为NULL。没有干净的方法来阻止这种情况,仅在单个表中使用约束即可。CHECK
约束不考虑其他行(没有肮脏的技巧)。
有关:
更新:
BEGIN;
UPDATE taxrate SET standard = NULL WHERE standard;
UPDATE taxrate SET standard = TRUE WHERE taxrate = 2;
COMMIT;
要允许这样的命令(仅在语句末尾满足约束条件):
WITH kingdead AS (
UPDATE taxrate
SET standard = NULL
WHERE standard
)
UPDATE taxrate
SET standard = TRUE
WHERE taxrate = 1;
.. UNIQUE
约束必须是DEFERRABLE
。看到:
dbfiddle 在这里
变体2
有第二个表,其中有一行,例如:
以超级用户身份创建它:
CREATE TABLE taxrate (
taxrate int PRIMARY KEY
);
CREATE TABLE taxrate_standard (
taxrate int PRIMARY KEY REFERENCES taxrate
);
CREATE UNIQUE INDEX taxrate_standard_singleton ON taxrate_standard ((true)); -- singleton
REVOKE DELETE ON TABLE taxrate_standard FROM public; -- can't delete
INSERT INTO taxrate (taxrate) VALUES (42);
INSERT INTO taxrate_standard (taxrate) VALUES (42);
现在总是有一行指向标准(在这种简单情况下,也直接代表标准汇率)。只有超级用户才能破解它。您也可以通过触发器禁止这样做BEFORE DELETE
。
dbfiddle 在这里
有关:
您可以添加一个VIEW
以与变体1相同:
CREATE VIEW taxrate_combined AS
SELECT t.*, (ts.taxrate = t.taxrate) AS standard
FROM taxrate t
LEFT JOIN taxrate_standard ts USING (taxrate);
在您只需要标准费率的查询中,taxrate_standard.taxrate
直接使用(仅)。
您后来添加了:
products.tax_rate_id
和之间有一个FKtax_rate.id
一个穷人的实现变型2的是只增加一排products
指着标准税率(或任何类似的表); 如果您的设置允许,您可以将其称为“标准税率”。
FK约束强制执行参照完整性。要完成此操作,请强制执行tax_rate_id IS NOT NULL
该行(如果通常情况下不是该列)。并禁止其删除。两者都可以触发。没有多余的桌子,但不太优雅,也不可靠。