2

我有一种情况,我试图从本质上获取两个时间点之间数据集上发生的所有更改的列表。这似乎是 Oracle 中 VERSIONS BETWEEN 关键字的一个很好的案例,但我不知道如何有效地加入其他表并获得我想要的结果。

假设我有以下表格:

CREATE TABLE emp (
    emp_id        NUMBER(5) PRIMARY KEY,
    employee_name VARCHAR2(20)
    dept_id       NUMBER(3) NOT NULL
                     CONSTRAINT admin_dept_fkey REFERENCES dept
                     (dept_id))
);

CREATE TABLE dept(
    dept_id    NUMBER(5),
    department VARCHAR2(20)
);

如果员工记录发生更改,我需要能够获取员工记录更改时的部门名称,因为该员工可能仍属于同一部门,但部门名称在某个时候已更改。

示例:EMP.VERSIONS_STARTSCN EMP_ID EMPLOYEE_NAME DEPT_ID DEPARTMENT 1 1 Michael 1 服务 0 1 Michael 1 销售

如果数据库是非规范化的并且我将部门名称存储在表本身上,这将非常容易;但是,使用查找表似乎不太直观。

我尝试过的事情:

SELECT *
FROM emp VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE e
JOIN dept d ON d.dept_id = e.dept_id;

这将为我提供今天存在的部门,但这并不能告诉我更改员工记录时它是什么。

SELECT *
FROM emp VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE e
JOIN dept VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE d
ON d.dept_id = e.dept_id;

这也不好,因为它将返回多行,一个用于每个部门更改的员工,而我实际上只想要更改员工记录时存在的部门。

我也尝试了几个内部选择,但似乎 Oracle 不允许我在内部查询中使用 VERSIONS_ENDSCN 或 VERSIONS_STARTTIME。我尝试过的变体包括:

SELECT 
    versions_startscn,
    e.employee_name,
    (SELECT department FROM dept AS OF SCN versions_startscn d WHERE d.dept_id = e.dept_id)
FROM emp VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE e

SELECT 
    e.employee_name
    (SELECT department FROM dept AS OF SCN versions_startscn d WHERE d.dept_id = e.dept_id)
FROM(
    SELECT 
        versions_startscn,
        e.employee_name,
    FROM emp VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE e
    )

这两个查询都会抛出未声明 VERSIONS_STARTSCN 的错误。

我觉得这必须是一个相当常见的用例,但我无法找到任何将 VERSIONS BETWEEN 与连接一起使用的示例。我想出了一种方法来做到这一点,包括打开一个游标,其中员工在 SCN MINVALUE 和 MAXVALUE 之间进行更改,将 SCN 选择为变量,然后从 emp 表和 DEPT AS OF SCN 中选择更改为嵌套表类型,但这似乎需要做很多看起来相当简单的事情。如果有人有任何想法,将不胜感激。

我目前正在使用 v11.2.0.4。

4

1 回答 1

0

我有几乎相似的要求

我只能通过检查一个表的版本时间是否介于另一表的版本时间之间来考虑这样做。start 或 Endtime 应该存在于其他表的开始和结束时间之间,反之亦然。但这是非常昂贵且缓慢的。

nvl(tblB.versions_Endtime,tblB.versions_starttime) >=  tblA.versions_starttime and  nvl(tblB.versions_Endtime,tblB.versions_starttime) <=  nvl(tblA.versions_endtime, to_timestamp('9999-01-01 00:00:00','YYYY-MM-DD HH:MI:SS'))

或者

nvl(tblA.versions_Endtime,tblA.versions_starttime) >=  tblB.versions_starttime and 
nvl(tblA.versions_Endtime,tblA.versions_starttime) <=  nvl(tblB.versions_endtime, to_timestamp('9999-01-01 00:00:00','YYYY-MM-DD HH:MI:SS'))
于 2019-10-19T14:39:10.087 回答