我有一张基本上是'元数据表'的表格;它记录了对另一个表的数据所做的更改,由于设计缺陷而增加了警告,我们无法执行SQL update
操作,并且当行上只有1个字段时必须删除然后重新插入行已更改,每行仅记录每个字段。例如:
Table Customers:
Customer ID | Customer Name | Customer Address |
001 | John F | 213 Privet Drive
002 | Kyle A | 16 Gammon Road
Table Customers-History:
TIMESTAMP | OPERATION | FIELD NAME | FIELD VALUE
1-Dec-2010 19:54:1232| INSERT | CUSTOMER ID | 001
1-Dec-2010 19:54:1232| INSERT | CUSTOMER NAME | Kyle A
1-Dec-2010 19:54:1500| INSERT | CUSTOMER ADDRESS | 10 Gammon Road
2-Dec-2010 09:54:9432| DElETE | CUSTOMER ID | 001
2-Dec-2010 09:54:9500| DELETE | CUSTOMER NAME | Kyle A
2-Dec-2010 09:54:9600| DELETE | CUSTOMER ADDRESS | 10 Gammon Road
2-Dec-2010 09:54:9800| INSERT | CUSTOMER ID | 001
2-Dec-2010 09:54:9900| INSERT | CUSTOMER NAME | Kyle A
2-Dec-2010 09:54:9600| INSERT | CUSTOMER ADDRESS | 16 Gammon Road
2-Dec-2010 09:55:9921| DELETE | CUSTOMER NAME | Josh C
2-Dec-2010 09:55:9925| DELETE | CUSTOMER ADDRESS| 2 Agin Court
因此,从上面的例子中,我们看到一位名叫Kyle A的顾客住在10 Gammon Road,然后第二天将地址更新为16 Gammon Road。过了一会儿,客户Josh C被删除了。您会注意到,虽然只编辑了customer address
,但整个行被删除后,customer name
也被注册为已删除并重新插入。因此,名称字段看起来更新了,但实际上并非如此 - 它是customer address
上编辑的一部分。
我想根据操作时间戳和字段名称将delete
- insert
操作分组为update
,向用户显示它实际上是update
操作并且可能只显示已更新的字段 - 在这种情况下,隐藏customer address
的结果。
我的问题是,这是否可能在SQL级别上(因为它返回结果最快)?如果没有,我可以在SQL查询中探索哪些策略来尽可能返回最小的相关结果,然后可以将其传递给另一个要处理的组件?
答案 0 :(得分:3)
如果我理解正确,INSERT
或DELETE
被视为UPDATE
,当且仅当:
INSERT
为UPDATE
- 记录为INSERTed
后DELETEed
DELETE
作为UPDATE
- 记录为DELETEDed
之前INSERTed
INSERT
或DELETE
的操作,无论哪种情况虽然[3]很简单,[1]和[2]会产生问题,因为您需要一个键来识别是否插入了 相同的 记录它已被删除,以便您可以将其标记为更新。只有在INSERT
或DELETE
中有可能不会更改的密钥时,才能确保此处的 相同 部分。由于此问题的性质,我认为密钥必须是NATURAL
而不是SURROGATE
。
在这种情况下可以使用以下策略:
步骤1:使用DELETE PRECEDING或INSERT FOLLOWING标志数据查询所有PK行
第2步:将所有INSERT或DELETE记录标记为满足我们条件的UPDATE
步骤3:将当前2条记录[由于步骤2]的UPDATE记录展平为单条记录
步骤4:使用UNION根据步骤3的结果集中的操作时间戳检索其他字段(示例中的客户地址)。
假设Customer Name
是您示例中缺少更好列的关键,以下伪SQL代码概述了解决问题核心的方法[仅限步骤1和2]。步骤3,4应该足够简单,可以在外部查询中添加]
SELECT /* 2nd step: Modify Operations to 'Update' if this INSERT id done after a DELETE or DELETE done afteran INSERT */
CASE
WHEN
OPERATION='INSERT' AND IS_DELETE_PRECEDING_FLAG=1
THEN
'UPDATE'
WHEN
OPERATION='DELETE' AND IS_INSERT_FOLLOWING_FLAG=1
THEN
'UPDATE'
ELSE OPERATION
END AS OPERATION,
FIELDNAME,
FIELDVAL,
OPDATE
(
SELECT /* 1st step: Query all PK records and also the flag information commented below */
OPERATION,
FIELDNAME,
FIELDVAL,
OPDATE,
IS_DELETE_PRECEDING_FLAG, --Pseudo Column using Oracle analytics, grouped using the customer name. Is 1 when there is a DELETE preceding, 0 otherwise
IS_INSERT_FOLLOWING_FLAG --Pseudo Column using Oracle analytics, grouped using the customer name. Is 1 when there is a INSERT following, 0 otherwise
FROM
CUST_TAB_HIST
WHERE
FIELDNAME='CUSTOMER NAME' --Assuming this is the primary key
)
;