一个解决方案是使用第二个表来检测冲突,并用触发器填充该表。使用你加入到这个问题的模式:
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