バリアント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
次のような単一の行を持つ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
関連:
バリアント1VIEW
と同じように表示するには、a を追加します。
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
との間にFKがありますtax_rate.id
貧乏人の実装変形形態2のだけに行を追加することでproducts
、標準税率を指す(または任意の同様のテーブル)。「標準税率」と呼ぶかもしれないダミー製品-セットアップで許可されている場合。
FK制約は、参照整合性を適用します。それを完了するにtax_rate_id IS NOT NULL
は、行を強制します(それが一般的に列に当てはまらない場合)。そして、その削除を禁止します。どちらもトリガーに入れることができます。余分なテーブルはありませんが、エレガントさが低く、信頼性が低くなります。