【发布时间】:2018-10-10 18:06:48
【问题描述】:
我正在尝试编写一个 Oracle 程序。我有一张桌子,目前我正在使用合并语句。当一条记录发生变化时,它会更新它,如果它是新的,它会添加它。
但是,我们希望跟踪更改的记录。所以我添加了三个字段:startdate、enddate、currentflag。如果有任何更改,我不想更新记录,我想添加一条新记录。但我确实想添加一个结束日期并更改旧记录上的标志。
所以,如果我有这样一张桌子:
TableID
Field1
Field2
Field3
StartDate
EndDate
CurrentFlag
它有这样的数据
TableID Field1 Field2 Field3 StartDate EndDate CurrentFlag
001 DataA Cow Brown 3-Oct-18 Y
001 DataA Cow White 1-Sep-18 3-Oct-18 N
002 DataB Horse Dapple 3-Oct-18 Y
我想合并一些数据
TableID Field1 Field2 Field3
001 NewData Cow Black
002 DataB Horse Dapple
005 Data3 Cat Black
让决赛桌看起来像这样
TableID Field1 Field2 Field3 StartDate EndDate CurrentFlag
001 DataA Cow Brown 3-Oct-18 10-Oct-18 N
001 DataA Cow White 1-Sep-18 3-Oct-18 N
001 NewData Cow Black 10-Oct-18 Y
002 DataB Horse Dapple 3-Oct-18 Y
005 Data3 Cat Black 10-Oct-18 Y
我的伪代码是
for each record in source file
find current record in dest table (on ID and flag = Y)
if any other fields do not match (Field1, Field2, Field3)
then update current record, set enddate, current flag to n
and add new record with startdate = sysdate, current flag is Y
if no match found, then add new record with startdate = sysdate, current flag is Y
我不确定如何将该伪代码转换为 Oracle SQL 代码。我可以使用相同的 MERGE 语句,但在 WHEN MATCHED 中添加检查以查看其他字段是否不同?
我将为几个表执行此操作,其中一些表有很多记录和很多字段。所以我需要找出一些可行的方法,而且不像糖蜜那么慢。
更新 我按照建议创建了一个程序,并进行了一些修改,所以它可以工作:
CREATE OR REPLACE PROCEDURE TESTPROC AS
BEGIN
DECLARE
l_count NUMBER;
CURSOR TRN is
SELECT * from sourceTable;
BEGIN
FOR each_record IN TRN
LOOP
-- if a record found but fields differ ...
l_count := 0;
SELECT COUNT(*) INTO l_count
FROM destTable DIM
WHERE each_record.TableID = DIM.TableID
and (each_record.Field1 <> DIM.Field1
or each_record.Field2 <> DIM.Field2
or each_record.Field13 <> DIM.Field3)
AND DIM.CurrentFlag = 'Y';
-- ... then update existing current record, and add with new data
IF l_count > 0 THEN
UPDATE destTable DIM
SET EndDate = sysdate
,CurrentFlag = 'N'
WHERE each_record.TableID = DIM.TableID;
INSERT INTO destTable
(TableID
, Field1
, Field2
, Field3
, StartDate
, CurrentFlag)
VALUES (each_record.TableID
, each_record.Field1
, each_record.Field2
, each_record.Field3
, sysdate
, 'Y');
COMMIT;
END IF;
-- if no record found with this key...
l_count := 0;
SELECT COUNT(*) INTO l_count
FROM destTable DIM
WHERE each_record.TableID = DIM.TableID;
-- then add a new record
IF l_count = 0 THEN
INSERT INTO destTable
(TableID
, Field1
, Field2
, Field3
, StartDate
, CurrentFlag)
VALUES (each_record.TableID
, each_record.Field1
, each_record.Field2
, each_record.Field3
, sysdate
, 'Y');
END IF;
END LOOP;
COMMIT;
END;
END TESTPROC
在我的小桌子上,效果很好。现在我正在我的一个较大的表(800k 记录,但绝不是最大的表)上尝试它,并且在它运行时我正在更新这个问题。已经快一个小时了,显然这是不可接受的。一旦我的程序返回,我将在 TableID、TableID 和 CurrentFlag 上添加索引。如果指数没有帮助,对于糖蜜方面的缓慢方面有什么建议吗?
【问题讨论】: