问题解决 SLT写入数据库NULL值

前言

最近项目上使用SLT(SAP Landscape Transformation,是一个实时数据复制工具,主要用于将数据从源系统(如SAP ERP或非SAP系统)复制到目标系统)把SAP数据同步到ORACLE数据库. 碰到初始化日期需要写入ORACLE数据库NULL值的问题

本文主要介绍SLT写入ORACLE数据库NULL值的方法

本文主要处理SAP空日期写入ORACLE数据库NULL值.其它类型可以参照实现

日期写入ORACLE还需注意,详见连接

无峰,公众号:ABAP 技巧与实战问题解决 SLT同步日期格式字段

日期初始值

SAP中日期的初始值 00000000 ,该日期无法写入ORACLE的日期字段. 用户希望当SAP日期是初始值时, 写入ORACLE日期字段NULL值.

日期00000000 SLT传输到目标日期类型的字段中时,报错 DMC_RT_MSG167

f9d18282ce0a2d5084b5f5e547d7072e.png

通过SM21查找具体SQL错误 ORA-01843 NOT A VALID MONTH 

fa469c003da8d4f1f4b89a268d8f4db3.png

关于NULL值

ABAP中NULL值的相关信息

ABAP环境的数据定义不允许NULL值

SE11定义数据字典时, 有个初始值选项. 但似乎勾选无效

af60b1aed78632cb53839c247591523a.png

通过显示表的数据库对象, 可以看到, 不管数据字典SE11中是否勾选初始值, 产生的HANA数据库中的字段都不支持初始值

7c40aa0be6c176aad5d9fddaf207062f.png

59013e3c240691f8a009ad416d49f9f9.png

ABAP中NULL值的产生原因一

一般情况下,视图LEFT JOIN 的右表,如果没有记录, 会生成NULL值, 此时需要通过语句 IS NULL 去访问 

比如EXORD 是关联右表的字段. EXORD IS NULL ,通过 EXORD = '' 无法访问到数据

视图中消除NULL值

可以通过 COALESCE(spfli.distance, 0) as distance_with_default 设置NULL的默认值

1c479ae11e867e03b0e56fe0cc582056.png

ABAP中NULL值产生原因二

表新增了字段,新增字段的内容系统设置为NULL值. 

SLT对NULL值的支持

如NOTES 2684480所述, SLT不支持从 SAP system 同步到ORACLE 表字段NULL值

57635be3b5802a621db0fa4828794c65.png

分析

SLT究其根本, 有如下处理逻辑:

  • 获取源系统的数据变化

  • 从源系统读取变化的数据

  • 写入目标系统

尝试找到写入目标系统的代码,研究调整使其支持写入NULL值即可.

方法

通过修改SLT写入程序实现NULL值写入ORACLE数据库

找到SLT配置的同步表(TCODE: LTRC)

bce233ca5160018a27439f912a80c280.png

双击查看生成的对象(需要注意的是: SLT初始化过程生成一个函数组,初始化后会删除之前的函数组,生成一个新的函数组. 最好源表数据为空, 让SLT快速初始化通过,生成最终执行的函数组, 在这个函数组的写入函数中修改代码. 下面的代码修改也支持初始化的函数组中的函数修改. 源表数据非空的情况下,需要两次修改函数)

07eda7c1c94217d7bc252f4b4dbb8ff7.png

e51533091afd94491b13a0b9dd302d67.png

5f2bb874d14b62bb931f4755dcafabf0.png

对应的函数代码. 

这里区分了 写入,更新,删除三个部分.图示了更新部分

4758129d3f7e7ac903dee26bde458e47.png

同义词

这里有个奇怪的地方: 同步的表 ZTTS_SLT . ORACLE中也创建了ZTTS_SLT . 但是生成的函数中写入的表是 /1LT/10000000389

24f7233d37f275156335dcb9ba44b02c.png

0825794407960e59be93d82cf1b377a9.png

'/1LT/10000000389' 是表的ZTTS_SLT的同义词. SLT 为了使用OPEN SQL 更新ORACLE表, 采用了同义词. 该同义词在SE11中存在表,但是数据库定义不同于SE11定义

如下图是 SE11(SLT中) 定义 和 SLT数据库中定义 及  ORACLE表定义的区别. 看起来SLT定义同义词的目的是为了使用OPEN SQL语句操作目标ORACLE数据库表

927eba1fc81002f0ffe3512b04afad00.png

技术难点

ORACLE支持的最小日期是 00010101 . 尝试写入00000000会报错.

因此调整标准代码中写入,更新部分的内容00000000->00010101

标准程序写入数据后, 再把所有00010101的字段通过NATIVE SQL 更新成 NULL值.

思路比较简单,但具体实现NATIVE SQL 执行动态SQL却费了很大的功夫

最终发现, 只有通过调用存储过程, 才能实现动态UPDATE 语句

过程如下

1. ORACLE中创建存储过程

CREATE OR REPLACE PROCEDURE execute_dynamic_sql (

p_sql_statement IN VARCHAR2)

IS

BEGIN

EXECUTE IMMEDIATE p_sql_statement;

EXCEPTION

WHEN OTHERS THEN

ROLLBACK;

RAISE;

END execute_dynamic_sql;

2. ABAP中动态生成SQL语句,调用存储过程

7b241d8c1d91685c8e6df8e9800470b1.png

为何不使用ADBC

NATIVE SQL动态更新数据碰到了很多麻烦. 在无数次和AI的沟通中, AI都建议使用ADBC实现动态语句更新数据(实现简单)

但因为标准生成的代码

insert /1lt/10000000389 client specified connection (con_name) 已经创建了一个数据库连接.

  commit connection (con_name).

NATIVE SQL 可以直接使用这个连接

 exec sql.       

   SET CONNECTION :con_NAME

endexec.

但是ADBC需要创建自己的连接.

在提交前创建连接会失败. 

但如果放到提交后再更新. 更新为NULL值的语句和写入语句就不再一个事务中. 这样会导致其它系统可能会读取到 00010101 的初始化日期.

最终实现

封装类 ZCL_SLT_WRITE_DATUM_NULL

50d62d4110409cef0b2214955531c9e2.png

类构造方法中读取传入表的字段

9ccb7c33e824868eddc7547e0fe247b5.png

CONVERT_DATUM方法负责动态把所有日期字段为00000000的转换成 00010101

2ca2938be3dcc290a809c8e7b44b3cef.png

UPDATE_NULL 负责在标准程序提交前,构造动态SQL把日期00010101更新成NULL值

726dd477766cb661e3f4b639322f0ea3.png

标准写入函数的修改

在函数开始时替换传入的数据内容,需要考虑替换写入表和更新表

afbcbb5182fc021017cd804a6e5ce821.png

在提交数据库之前先更新数据为NULL

31cf5a87e07693c16c17907f5639a68f.png

34a1ff879fe6e202e449fd9e75880033.png

实测通过

测试表ZTTS_SLT中新增或修改的记录的空日期,写入ORACLE系统值为NULL

8b3f98aa06a614197995ff784ccc3770.png

十一

总结

SLT把初始化日期写入目标ORACLE数据库NULL值,无法通过标准功能实现. 需要通过重写SLT生成的数据库写入函数. 因为该函数在配置LTRC时生成,并且生成的函数名可能与开发系统不一致. 所以需要在生产系统中直接修改函数,添加相关代码实现更新NULL值

SLT生成的写入目标数据库的代码没有使用ADBC的方法. 可能的原因

  • 性能考虑, NATIVE SQL 性能可能好于ADBC

  • 版本原因,SLT最初版的产品可能还无法使用ADBC

感觉可以在这里改进一下, 改用ADBC,同时预留出口, 以便客户实现更多样化的目标数据库内容写入

SLT 初始化对象是会生成一个函数组.初始化后会生成另外一个函数组. 

SLT全局类型映射可能会导致在目标数据库创建表失败. (不确定这个BUG新版本是否修复). 最好使用表+字段级别的类型映射

THE

END

约定

如果你对这篇文章感兴趣,请帮忙点赞,在看,分享.       

请微信联系管理员: 

syjf1976 

sharry_xlp  

Yannick_Duan 

申请进入公众号讨论群提问或者参与话题讨论