一個解決方案是使用第二個表來檢測衝突,並用觸發器填充該表。使用你加入到這個問題的模式:
CREATE TABLE medicinal_product_date_map(
aic_code char(9) NOT NULL,
applicable_date date NOT NULL,
UNIQUE(aic_code, applicable_date));
(注:這是第二次嘗試,由於誤讀您的要求在第一時間輪希望這是正確的這個時候。)。
一些功能,以保持該表:
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 applicable_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;
$$;
CREATE TRIGGER sync_date_map
AFTER INSERT OR UPDATE OR DELETE ON medicinal_products
FOR EACH ROW EXECUTE PROCEDURE 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');
ERROR: duplicate key value violates unique constraint "medicinal_product_date_map_aic_code_applicable_date_key"
DETAIL: Key (aic_code, applicable_date)=(1 , 2010-03-01) already exists.
CONTEXT: SQL function "add_medicinal_product_date_range" statement 1
SQL statement "SELECT add_medicinal_product_date_range(NEW.aic_code, NEW.vs, NEW.ve)"
PL/pgSQL function "sync_medicinal_product_date_map" line 6 at PERFORM
這取決於的值被檢查爲具有離散空間 - 這就是爲什麼我詢問了日期與時間戳。雖然時間戳在技術上是離散的,因爲Postgresql只存儲微秒分辨率,但在每一微秒增加一個條目到映射表中,該產品適用於此是不實際的。儘管如此,你也許還可以得到比全表掃描更好的東西來檢查重疊的時間戳記間隔,並且在僅僅尋找第一個間隔之前或之前不尋找......但是,對於易於離散的空間,我更喜歡這種方法,即IME也可以用於其他方面(例如需要快速查找哪些產品適用於某一天的報告)。
我也喜歡這種方法,因爲這種方式充分利用了數據庫的唯一性約束機制。另外,我覺得在主表的併發更新的情況下它會更可靠:在不鎖定併發更新的情況下,驗證觸發器可能看不到衝突,並允許插入兩個併發會話,即然後在兩個交易的影響都可見時發生衝突。
您在評論中提到一個答案,即使用DATE列存儲有效時間。那麼你能否澄清一下,實際上你只是在檢查日期衝突,而不是完整的時間戳? – araqnid 2010-06-09 15:14:48