使用合并在 Oracle 触发器中实现类型 II SCD
Implement type II SCD in Oracle trigger with using merge
我这辈子都无法使以下查询正常工作……本质上它是对以下票证的修改:
.
CREATE OR REPLACE TRIGGER TABLE_UPDATE
AFTER INSERT OR UPDATE ON DIM_TABLE
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF INSERTING OR UPDATING
THEN
MERGE INTO DIM_TABLE T_1
USING( SELECT COL_1, max(VALID_FROM) AS LAST_DATE FROM
DIM_TABLE
GROUP BY COL_1) T_2
ON (T_1. COL_1= T_2. COL_1)
WHEN NOT MATCHED THEN INSERT (T_1. VALID_FROM) VALUES(SYSDATE)
WHEN MATCHED THEN
UPDATE
SET T_1.VALID_UNTIL = T_2.LAST_DATE
WHERE T_1. VALID_UNTIL is null
AND T_1. VALID_FROM <> T_2.LAST_DATE;
COMMIT;
END IF;
END;
所需功能:将值输入数据库 (COL_1)。
如果该列没有匹配项,则 VALID_FROM 日期将作为 sysdate 输入。如果存在匹配项,则脚本应更新前一行的 VALID_UNTIL 值(直到现在为空,因为它仍然有效)。
我不断收到以下错误:
死锁和递归的最大级别超过 (50)
我真的很难满足你的要求。在我看来,您似乎希望 VALID_FROM
成为 sysdate
或每个 COL_1
.
的最大值
我会通过使用 :NEW
来操作当前行
set linesize 250
drop table dim_Table;
create table dim_table (col_1 varchar2(50), valid_from timestamp);
CREATE OR REPLACE TRIGGER TABLE_UPDATE
before INSERT OR UPDATE ON DIM_TABLE
FOR EACH ROW
DECLARE
l_valid_from date;
BEGIN
select max(valid_from)
into l_valid_from
from dim_table t1
where t1.col_1 = :new.col_1;
if l_valid_from is null then
:new.valid_from := sysdate;
else
:new.valid_from := l_valid_from;
end if;
END;
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST2');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST2');
select * from dim_table;
输出:
Table dropped.
Table created.
Trigger created.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
1 row selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
2 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
3 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
TEST1 30/04/2019 09:13:10.000000
4 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
5 rows selected.
谢谢@hol,@Alex Poole,我想我破解了它。
每次添加任何内容时,我都使用触发器将数据插入 VALID_FROM:
CREATE TABLE "DIM_TEST" ( "COL_1" VARCHAR2(20 BYTE), "VALID_UNTIL" TIMESTAMP (6),
"DIM_TEST_PK" NUMBER, "VALID_FROM" TIMESTAMP (6) DEFAULT NULL)
create or replace TRIGGER T_DIM_TEST_DATE_INSERT
BEFORE INSERT ON DIM_TEST
FOR EACH ROW
BEGIN
:new.VALID_FROM := sysdate;
END;
对于在添加重复项时更新前一行 VALID_FROM 的部分,我有以下触发器:
create or replace TRIGGER TABLE_UPDATE
after INSERT or update
ON DIM_TEST
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF INSERTING
THEN
MERGE INTO DIM_TEST T_1
USING (select :new.COL_1 from DUAL) T_2
ON (T_1.COL_1 = :new.COL_1)
WHEN MATCHED THEN
UPDATE
SET T_1.VALID_UNTIL = (SYSDATE)
WHERE T_1. VALID_UNTIL is null;
--AND T_1. VALID_FROM <> (SELECT max(VALID_FROM) FROM DIM_TEST);
END IF;
COMMIT;
END;
唯一的缺点是,如果将现有行更新为重复行,则第二个触发器将不会触发,因为 IF INSERTING 子句...当我将其更改为
IF INSERTING or UPDATING 那么它会产生一个无限循环...但我可以限制用户只能插入所以这应该不是问题。
我这辈子都无法使以下查询正常工作……本质上它是对以下票证的修改:
CREATE OR REPLACE TRIGGER TABLE_UPDATE
AFTER INSERT OR UPDATE ON DIM_TABLE
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF INSERTING OR UPDATING
THEN
MERGE INTO DIM_TABLE T_1
USING( SELECT COL_1, max(VALID_FROM) AS LAST_DATE FROM
DIM_TABLE
GROUP BY COL_1) T_2
ON (T_1. COL_1= T_2. COL_1)
WHEN NOT MATCHED THEN INSERT (T_1. VALID_FROM) VALUES(SYSDATE)
WHEN MATCHED THEN
UPDATE
SET T_1.VALID_UNTIL = T_2.LAST_DATE
WHERE T_1. VALID_UNTIL is null
AND T_1. VALID_FROM <> T_2.LAST_DATE;
COMMIT;
END IF;
END;
所需功能:将值输入数据库 (COL_1)。 如果该列没有匹配项,则 VALID_FROM 日期将作为 sysdate 输入。如果存在匹配项,则脚本应更新前一行的 VALID_UNTIL 值(直到现在为空,因为它仍然有效)。
我不断收到以下错误: 死锁和递归的最大级别超过 (50)
我真的很难满足你的要求。在我看来,您似乎希望 VALID_FROM
成为 sysdate
或每个 COL_1
.
我会通过使用 :NEW
来操作当前行
set linesize 250
drop table dim_Table;
create table dim_table (col_1 varchar2(50), valid_from timestamp);
CREATE OR REPLACE TRIGGER TABLE_UPDATE
before INSERT OR UPDATE ON DIM_TABLE
FOR EACH ROW
DECLARE
l_valid_from date;
BEGIN
select max(valid_from)
into l_valid_from
from dim_table t1
where t1.col_1 = :new.col_1;
if l_valid_from is null then
:new.valid_from := sysdate;
else
:new.valid_from := l_valid_from;
end if;
END;
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST2');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST1');
select * from dim_table;
exec dbms_lock.sleep(1);
insert into dim_table (col_1) values ('TEST2');
select * from dim_table;
输出:
Table dropped.
Table created.
Trigger created.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
1 row selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
2 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
3 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
TEST1 30/04/2019 09:13:10.000000
4 rows selected.
PL/SQL procedure successfully completed.
1 row created.
COL_1 VALID_FROM
-------------------------------------------------- --------------------------------------------------
TEST1 30/04/2019 09:13:10.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
TEST1 30/04/2019 09:13:10.000000
TEST2 30/04/2019 09:13:12.000000
5 rows selected.
谢谢@hol,@Alex Poole,我想我破解了它。 每次添加任何内容时,我都使用触发器将数据插入 VALID_FROM:
CREATE TABLE "DIM_TEST" ( "COL_1" VARCHAR2(20 BYTE), "VALID_UNTIL" TIMESTAMP (6),
"DIM_TEST_PK" NUMBER, "VALID_FROM" TIMESTAMP (6) DEFAULT NULL)
create or replace TRIGGER T_DIM_TEST_DATE_INSERT
BEFORE INSERT ON DIM_TEST
FOR EACH ROW
BEGIN
:new.VALID_FROM := sysdate;
END;
对于在添加重复项时更新前一行 VALID_FROM 的部分,我有以下触发器:
create or replace TRIGGER TABLE_UPDATE
after INSERT or update
ON DIM_TEST
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF INSERTING
THEN
MERGE INTO DIM_TEST T_1
USING (select :new.COL_1 from DUAL) T_2
ON (T_1.COL_1 = :new.COL_1)
WHEN MATCHED THEN
UPDATE
SET T_1.VALID_UNTIL = (SYSDATE)
WHERE T_1. VALID_UNTIL is null;
--AND T_1. VALID_FROM <> (SELECT max(VALID_FROM) FROM DIM_TEST);
END IF;
COMMIT;
END;
唯一的缺点是,如果将现有行更新为重复行,则第二个触发器将不会触发,因为 IF INSERTING 子句...当我将其更改为 IF INSERTING or UPDATING 那么它会产生一个无限循环...但我可以限制用户只能插入所以这应该不是问题。