ODI中删除数据的处理

一、前提知识:
数据从源数据库向数据仓库抽取时,一般采用以下几种方式:

  • 全抽取模式
    如果表的数据量较小,则可以采取全表抽取方式,以TRUNCATE/INSERT方式进行数据抽取。
  • 基于时间戳的抽取模式
    如果源数据表是不可更新的数据(如大多数事务处理数据)或者是不可删除数据(只能失效历史记录的情况),则根据变更时间戳,抽取最新变更的数据进行同步。
  • 日志分析
    如果没有更新时间戳,或者源数据存在删除的情况,则可以进行日志分析,来执行最新数据变更的同步。

说明:时间戳的方式如果要处理删除数据的情况,需要在源表创建触发器来捕获删除的记录。
ODI在数据抽取方面,添加了CDC(Changed Data Capture)的功能,并且包含两种方式,一种是在源数据库表上增加触发器来捕获新增、修改和删除的数据到日志表中。另一种是通过对日志的挖掘(Oracle的Log Miner和IBM DB2/400)。但是ODI的CDC,必须要求源表有主键。
二、删除数据的问题引入
当我们开始使用ODI来进行CDC方式的数据同步时,一切都正常,删除的数据也可以正确的同步到目标数据库。接着,因为业务需求,我们只需要同步部分数据到目标数据库,也就是为源数据表加上过滤,这样问题就出来了,新增和修改的数据都能正确的同步到目标数据库,而源数据表删除的数据,经过ODI Interface执行之后,目标数据表中还存在。
经过检查,Interface在装载数据时查询日志视图,而日志视图是日志表与源表的外连接,其结果是删除的记录在视图中只有主键,其余的字段都为空,这样基于日志视图上的过滤,必然导致删除的数据被过滤掉。以下是ODI创建的对象脚本示例:

数据源日志视图jv$qp_list_lines
create or replace view soau.jv$qp_list_lines as
SELECT decode(targ.ROWID, NULL, 'D', 'I') jrn_flag,
       jrn.jrn_subscriber jrn_subscriber,
       jrn.jrn_date jrn_date,
       jrn.list_line_id list_line_id,
       targ.creation_date creation_date,
       targ.created_by created_by,
       ...
FROM (SELECT l.jrn_subscriber jrn_subscriber, l.list_line_id list_line_id, MAX(l.jrn_date) jrn_date
FROM soau.j$qp_list_lines l
WHERE l.jrn_consumed = '1'
GROUP BY l.jrn_subscriber, l.list_line_id) jrn,
soau.qp_list_lines targ
WHERE jrn.list_line_id = targ.list_line_id(+)

ODI Interface创建用于装载数据的的临时视图
create or replace view
SOAU.C$_0QP_LIST_LINES
(
C1_LIST_LINE_ID,
C2_CREATION_DATE,
C3_CREATED_BY,
...
JRN_SUBSCRIBER,
JRN_FLAG,
JRN_DATE
)
as select
QP_LIST_LINES.LIST_LINE_ID,
QP_LIST_LINES.CREATION_DATE,
QP_LIST_LINES.CREATED_BY,
...
JRN_SUBSCRIBER,
JRN_FLAG,
JRN_DATE
from SOAU.JV$QP_LIST_LINES QP_LIST_LINES
where (1=1)
And (QP_LIST_LINES.LIST_LINE_TYPE_CODE IN ('PLL', 'PBH'))
And (QP_LIST_LINES.END_DATE_ACTIVE is null or trunc(QP_LIST_LINES.END_DATE_ACTIVE) > trunc(sysdate))
And (QP_LIST_LINES.PRICING_PHASE_ID = 1)
And (QP_LIST_LINES.QUALIFICATION_IND IN (4, 6, 20, 22))
AND JRN_SUBSCRIBER = 'ERP-FK' /* AND JRN_DATE < sysdate */


Interface在执行集成时,将数据从视图SOAU.C$_0QP_LIST_LINES插入到flow table(flow
table是Interface处理的位于目标中间表,数据的同步最终从flow
table到目标数据表),由于该视图已经执行了过滤,删除的数据就无法插入到flow table,导致删除的数据最终无法写入目标。
三、问题解决过程
因为数据在源头就被过滤了,所以必须保证数据在源头不被过滤,而Interface可以支持在源、Staging、目标来执行处理,那么就来做各种测试:
1、将数据过滤移到Staging
经过测试发现,虽然在装载数据时,包含了删除的记录,但是在集成阶段,数据插入flow table时,由于除了主键,其余字段都为空,所以删除的数据同样被过滤掉了。
2、将数据过滤移到目标
经过测试,当我们将过滤移到目标时,删除的数据被正确的同步到了目标表。那只要将过滤移到目标,就可以解决问题了?
3、新问题的出现
实际上数据插入flow table后,从flow table到目标表,没有执行任何过滤处理,所有数据都会被同步到目标数据表。这样我们需要排除的数据也写入了目标表,说明这个方式失败。
4、启用模型中目标表的过滤
在ODI Designer中,编辑Model下的表,添加过滤,然后将Interface中对源数据的过滤移除,执行Interface发现,数据正确的插入到了目标表。但是这种方式和前一种方式相同,都是把所有变化的数据都从源取到目标中,存在一定的性能问题。
5、最终的方式
经过研究,还是觉得修改ODI原来的LKM最为实际,只需要把从日志视图的取数的视图代码修改,修改为原来的视图代码UNION删除的记录即可。
修改后的Create view on source代码如下:

create or replace view <%=odiRef.getObjectNameDefaultPSchema("L", "" , "W")%><%=odiRef.getInfo("COLL_NAME")%>
(
<%=odiRef.getColList("", "[CX_COL_NAME]", ",/n/t", "", "")%>
)
as select <%=odiRef.getPop("DISTINCT_ROWS")%>
<%=odiRef.getColList("", "[EXPRESSION]", ",/n/t", "", "")%>
from <%=odiRef.getFrom()%>
where (1=1)
<%=odiRef.getFilter()%>
<%=odiRef.getJrnFilter()%>
<%=odiRef.getJoin()%>
<%=odiRef.getGrpBy()%>
<%=odiRef.getHaving()%>

<%if(!odiRef.getJrnFilter().equals("")){%>

UNION

select <%=odiRef.getPop("DISTINCT_ROWS")%>
<%=odiRef.getColList("", "[EXPRESSION]", ",/n/t", "", "")%>
from <%=odiRef.getFrom()%>
where (1=1)
<%=odiRef.getJrnFilter()%>
AND JRN_FLAG='D'
<%=odiRef.getJoin()%>
<%=odiRef.getGrpBy()%>
<%=odiRef.getHaving()%>

<%}%>
四、插曲
在问题有了解决方案之后,向Oracle提Tar,经过数次沟通,并最终在OWC演示的情况下,确认为KM的Bug。
不过Oracle又提供了一种处理方法,这种方法不需要修改LKM,但是看上去感觉总有点不那么好:在Interface中的每个Filter代码中,加入" OR JRN_FLAG = 'D'",这样就可以保证日志表中删除的记录一定不会被过滤掉。

本文转自:http://www.itjaj.com/viewthread.PHP?tid=4590&extra=page%3D1%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D88

ODI中删除数据的处理的更多相关文章

  1. NHibernate 中删除数据的几种方法

    今天下午有人在QQ群上问在NHibernate上如何根据条件删除多条数据,于是我自己就写了些测试代码,并总结了一下NHibernate中删除数据的方式,做个备忘.不过不能保证囊括所有的方式,如果还有别 ...

  2. 总结NHibernate 中删除数据的几种方法

    今天下午有人在QQ群上问在NHibernate上如何根据条件删除多条数据,于是我自己就写了些测试代码,并总结了一下NHibernate中删除数据的方式,做个备忘.不过不能保证囊括所有的方式,如果还有别 ...

  3. SQL语句的使用,SELECT - 从数据库表中获取数据 UPDATE - 更新数据库表中的数据 DELETE - 从数据库表中删除数据 INSERT INTO - 向数据库表中插入数据

    SQL DML 和 DDL 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL). SQL (结构化查询语言)是用于执行查询的语法. 但是 SQL 语言也包含用于更新. ...

  4. GDAL书籍中删除数据勘误(C#语言)

    GDAL书籍中关于C#版本删除数据的时候,不能完全删除数据,由于我对C#不了解导致代码有点问题,非常感谢@Bingoyin指出并给出修改方案.此外对于栅格图像的删除.重命名,矢量数据的删除和重命名都有 ...

  5. MySQL中删除数据的两种方法

    转自:http://blog.csdn.net/apache6/article/details/2778878 1. 在MySQL中有两种方法可以删除数据: 一种是delete语句,另一种是trunc ...

  6. SQL语句中—删除数据

    老大------drop 出没场合:droptable tb --tb表示数据表的名字,下同 绝招:删除内容和定义,释放空间.简单来说就是把整个表去掉.以后要新增数据是不可能的,除非新增一个表 老二- ...

  7. map在遍历数据的过程中删除数据不出错

    // Iterator<Map.Entry<String,Long>> entries = Map.entrySet().iterator();                 ...

  8. telerik:RadGrid 表格中删除数据

    <telerik:RadGrid OnItemCommand=" Height="490px" Culture="zh-CN" CssClass ...

  9. Sql Server删除数据表中重复记录 三种方法

    本文介绍了Sql Server数据库中删除数据表中重复记录的方法. [项目]数据库中users表,包含u_name,u_pwd两个字段,其中u_name存在重复项,现在要实现把重复的项删除![分析]1 ...

随机推荐

  1. HTML6注册表单输入日志标题

    一.找到元素. var d = document.getElementById("") var d = document.getElementsByName("" ...

  2. ubuntu mysql编码设置5.5以后

    安装了mysql. 版本:5.5.28 操作系统 :ubuntu 12.10 mysql> show variables like 'character%'; +---------------- ...

  3. Eclipse选中变量名,相同变量都变色显示 的设置

    ava文件的设置"Window"-"preferences"-"Java"-"Editor"-"Mark Oc ...

  4. Flink Program Guide (7) -- 容错 Fault Tolerance(DataStream API编程指导 -- For Java)

    false false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-n ...

  5. Log4J使用笔记(转)

    转自:http://www.cnblogs.com/eflylab/archive/2007/01/11/618001.html Log4J是Apache的一个开放源代码的项目.通过使用Log4J,程 ...

  6. matlab中文论坛视频谷普教程MATLAB压缩包介绍

    matlab中文论坛视频谷普教程MATLAB压缩包介绍 我也正在学习这个软件 ,看到这个教程就在这里分享了,希望大家喜欢!Matlab 初学者视频教学1. Matlab视频:Matlab中文论坛为新手 ...

  7. GDKOI 2016

    GDKOI 2016 day 1 第一题 魔卡少女 题目描述:维护一个序列,能进行以下两个操作:1.将某一个位置的值改变.2.求区间的连续子串的异或值的和. solution 因为序列的数的值都小于\ ...

  8. POJ——字符串插入

    2:字符串插入 查看 提交 统计 提问 总时间限制:  1000ms  内存限制:  65536kB 描述 有两个字符串str和substr,str的字符个数不超过10,substr的字符个数为3.( ...

  9. 依赖注入及AOP简述(十三)——AOP应用举例(完结) .

    2.     AOP应用举例 在一般的应用程序开发中,有一些典型的AOP应用,使得开发者可以专注于业务逻辑本身,而不是与之完全无关的一些“方面”. l        首先就是关于前面介绍过的日志输出类 ...

  10. android的二进制和十六进制的相互转换工具类(一):

    二进制和十六进制的相互转换工具类: package com.gzcivil.utils; public class BinStr { /** * 将二进制转换成16进制 * @param buf * ...