以更易读的格式显示此元数据表的策略?

时间:2014-10-15 15:40:50

标签: sql oracle11g oracle-sqldeveloper

我有一张基本上是'元数据表'的表格;它记录了对另一个表的数据所做的更改,由于设计缺陷而增加了警告,我们无法执行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查询中探索哪些策略来尽可能返回最小的相关结果,然后可以将其传递给另一个要处理的组件?

1 个答案:

答案 0 :(得分:3)

如果我理解正确,INSERTDELETE被视为UPDATE,当且仅当:

  1. INSERTUPDATE - 记录为INSERTedDELETEed
  2. DELETE作为UPDATE - 记录为DELETEDed之前INSERTed
  3. 在所有其他情况下,你会想要提出 作为独立INSERTDELETE的操作,无论哪种情况
  4. 虽然[3]很简单,[1]和[2]会产生问题,因为您需要一个键来识别是否插入了 相同的 记录它已被删除,以便您可以将其标记为更新。只有在INSERTDELETE中有可能不会更改的密钥时,才能确保此处的 相同 部分。由于此问题的性质,我认为密钥必须是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
      )  
    ;