【发布时间】:2011-06-22 17:03:17
【问题描述】:
鉴于此表:
CREATE TABLE DeptPeopleHistory (
DEPT_ID INTEGER,
PERSON_ID INTEGER,
START_DATE INTEGER,
END_DATE INTEGER,
UNIQUE(DEPT_ID, START_DATE, PERSON_ID), -- works as sorted index.
UNIQUE(PERSON_ID, START_DATE),
UNIQUE(PERSON_ID, END_DATE),
CONSTRAINT (START_DATE < END_DATE)
);
我有两个需求。首先是让所有在给定日期在给定部门工作的人。目前我使用这个(语义正确)查询:
SELECT PERSON_ID FROM DeptPeopleHistory
WHERE
DEPT_IT = :given_dept AND
START_DATE <= :given_date AND :given_date < END_DATE
这对于小的历史表或查询最近的数据来说很快,但对于大的历史表和旧数据来说速度很慢,因为优化器只使用第一个索引并且没有很好的方法来处理 END_DATE。我尝试将 END_DATE 添加到第一个索引,但查询性能是相同的。我猜这是因为子过滤器 (DEPT_IT=:given_dept AND START_DATE
我的另一个需要是强制执行以下约束:一个人不能同时在两个部门工作,也不能在同一个部门工作两次。这意味着:
-- This must work for previously empty data:
INSERT INTO DeptPeopleHistory(DEPT_ID, PERSON_ID, START_DATE, END_DATE)
VALUES (1, 1, 20100501, 20100520);
-- This should cause constraint violation because the person already
-- works at dept 1 on days from 20100517 to 20100519:
INSERT INTO DeptPeopleHistory(DEPT_ID, PERSON_ID, START_DATE, END_DATE)
VALUES (:any_dept, 1, 20100517, 20100523);
另一种指定此约束的方法是,对于给定的 PERSON_ID,START_DATE 必须是最小值或等于另一个记录的 END_DATE。
看看这两个需求,我们实际上需要一种有效的方法来处理不相交的范围。您是否知道通用 SQL 或某些特定数据库中的某些功能或构造无法满足这些需求?也许是一些“空间数据库”功能?
示例在 MySQL 中,但我需要适用于 Oracle、SQL Server 和 FireBird 的解决方案。这些解决方案不需要在所有此类数据库中都可移植。
【问题讨论】:
-
首先,mySQL 缺乏时态数据库所需的约束,例如您的表缺少排序的主键,即允许同一个人 + 部门的重叠日期;更新表格时,即使您的
START_DATE < END_DATE也不会被检查。其次,(假设您正在寻找开源的东西),无论如何,postgreSQL 都有更好的时间支持:)
标签: mysql sql indexing constraints spatial