1つの解決策は、衝突を検出するために使用する2番目のテーブルを用意し、それにトリガーを設定することです。質問に追加したスキーマの使用:
CREATE TABLE medicinal_product_date_map(aic_code char(9)NOT NULL、applicable_date date NOT NULL、UNIQUE(aic_code、applicable_date));
(注:最初のラウンドで要件を読み間違えたため、これは2回目の試行です。今回は正しいことを願っています)。
このテーブルを維持するためのいくつかの関数:
CREATE FUNCTION add_medicinal_product_date_range(aic_code_in char(9)、start_date date、end_date date)RETURNS void STRICT VOLATILE LANGUAGE sql AS $$ INSERT INTO medicinal_product_date_map SELECT $ 1、$ 2 + offset FROM generate_series(0、$ 3-$ 2)$ $; CREATE FUNCTION clr_medicinal_product_date_range(aic_code_in char(9)、start_date date、end_date date)RETURNS void STRICT VOLATILE LANGUAGE sql AS $$ DELETE FROM medicinal_product_date_map WHERE aic_code =$ 1 AND apply_date BETWEEN $ 2 AND $ 3 $$;
そして、最初にテーブルに次の情報を入力します:
SELECT count(add_medicinal_product_date_range(aic_code、vs、ve))FROM medicinal_products;
次に、medicinal_productsの変更後、日付マップにデータを入力するトリガーを作成します。挿入呼び出し後add_、更新呼び出し後clr_(古い値)およびadd_(新しい値)、削除呼び出し後clr_。
CREATE FUNCTION sync_medicinal_product_date_map()RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF TG_OP ='UPDATE' OR TG_OP ='DELETE' THEN PERFORM clr_medicinal_product_date_range(OLD.aic_code、OLD.vs、OLD.ve); END IF; IF TG_OP ='UPDATE' OR TG_OP ='INSERT' THEN PERFORM add_medicinal_product_date_range(NEW.aic_code、NEW.vs、NEW.ve); END IF; RETURN NULL; END; $$;各行の実行手順のmedicinal_productsの挿入、更新、または削除後にトリガーsync_date_mapを作成しますsync_medicinal_product_date_map();
medicinal_product_date_mapの一意性の制約により、同じ日に同じコードで追加されたすべての製品がトラップされます:
[email protected] @ [local] =#INSERT INTO medicinal_products VALUES( '1'、'A'、 '2010-01-01'、 '2010-04-01'); INSERT 0 1 [email protected] @ [local] =#INSERT INTO medicinal_products VALUES( '1'、'A'、 '2010-03-01'、 '2010-06-01');エラー:重複するキー値が一意の制約 "medicinal_product_date_map_aic_code_applicable_date_key"に違反しています詳細:キー(aic_code、applicable_date)=(1、2010-03-01)はすでに存在します。CONTEXT:SQL関数"add_medicinal_product_date_range"ステートメント1SQLステートメント"SELECT add_medicinal_product_date_range(NEW.aic_code、NEW.vs、NEW.ve)" PL/pgSQL関数" sync_medicinal_product_date_map"PERFORMの6行目
これは、離散スペースがあるかどうかをチェックする値によって異なります。そのため、日付とタイムスタンプについて質問しました。 Postgresqlはマイクロ秒の解像度しか保存しないため、タイムスタンプは技術的には離散的ですが、製品が適用されるマイクロ秒ごとにマップテーブルにエントリを追加することは実用的ではありません。
そうは言っても、タイムスタンプ間隔の重複をチェックするために全表スキャンよりも優れた方法を使用することもできます。ただし、簡単な離散空間の場合は、最初の間隔のみを検索するのは難しいです。私は、IMEが他のことにも役立つこのアプローチを好みます(たとえば、特定の日に適用可能な製品をすばやく見つける必要があるレポート)。
この方法でデータベースの一意性制約メカニズムを活用するのが正しいと感じるので、このアプローチも気に入っています。また、マスターテーブルへの同時更新のコンテキストでは、より信頼性が高いと思います。同時更新に対してテーブルをロックしなくても、検証トリガーで競合がないことを確認し、2つの同時セッションでの挿入を許可することができます。その後、両方のトランザクションの影響が表示されると、競合するように見えます。