SAP ABAP基础知识 访问外部数据库-开发篇

前言

本文主要介绍通过ABAP语言访问外部数据库的几种方式

一、外部数据库配置

本文示例中的代码访问了两个外部数据库

MTD : 外部oracle数据库,其中示例表 ZTTEMP 字段( ZZTNO,WERKS)

S4Q : 外部HANA数据库(开发系统访问测试系统的数据库), 使用表USR02,ZTTEMP

二、ABAP访问外部数据库

通过ABAP访问外部数据库有四种方式.根据不同的情况,可以选择不同的方法.

OPEN SQL访问
NATIVE SQL 访问
ADBC(ABAP Database Connectivity)
AMDP ABAP Managed Database Procedures ? (未验证通过)


 

三、OPEN SQL直接访问

OPEN SQL 访问的限制条件:必须在ABAP数据字典中存在该表名,并且最好同目标系统表结构一致, 一般情况下,用来访问另外一个同版本的ECC数据库.当然,也可以把ECC的表定义语句在目标系统中创建一个同名同结构的表,然后用该方式访问.

直接访问时,在FROM TABLE 后面添加 CONNECTION s4q .

s4q是DBCO中建立的和另外一个S/4系统的连接

01

报错及处理一

可能的报错及处理方式

下图报错的原因是访问ORACLE数据库必须指定一个SCHEMA. 这个可以配置在连接参数中.

01

报错及处理二

出现下面的报错,表示系统尝试使用MANDT限制数据, 此时需要给OPEN SQL 语句添加CLIENT SPECIFIED 强制OPEN SQL 不要补充MANDT限制

四、NATIVE SQL访问

通过NATIVE SQL 访问外部数据库步骤

打开连接
执行SQL命令
关闭连接
示例代码见文末

01

读取多条记录的方式

游标方式     


非游标方式


非游标方式其实隐式使用了游标.性能比游标方式要差.数据量小的时候看不出来. 大量数据读取就能看出二者的性能差异了. 

标准帮助中提示的优劣比较.

五、ADBC访问

ADBC(ABAP Database Connectivity) 是SAP提供的原生SQL(Native SQL)接口API.可以通过ADBC执行任何数据库的原生SQL语句.

ABAP中有个标准的DEMO程序: ADBC_DEMO 演示了各种SQL语句的调用方式.图四的代码示例给出了SELECT语句的常用写法.

大概需要如下的过程

创建默认数据库的链接对象
创建一个查询对象
基于sql语句创建一个结果对象
定义传递结果集一个数据对象-内表
获取数据内容
关闭连接
赋值数据到内表
示例代码详见文末

六、通过AMDP 访问?

AMDP ABAP Managed Database Procedures

标准ABAP帮助体系中提到访问外部数据库的方法中还有一种AMDP方式.为了完善本文,补充了一个AMDP访问外部数据库表的示例.(验证未通过)

尝试中发现AMDP只适用与HANA数据库. 并且尝试通过DEMO程序 DEMO_AMDP_CONNECTION 连接外部数据库S4Q. 尝试失败. (报错见图四)

感觉AMDP 并不支持连接外部数据库. 

图五中示例代码的连接 是 R/3*开头. 帮助中说S/3*是SERVICE CONNECT. 但是不理解有什么用

处.

 

七、总结

ABAP访问外部数据库的几种方式中. OPEN SQL 最简单,但是有很大局限性. NATIVE方式最简单易懂. 性能也最好. 但是不利于代码动态化. ADBC 可以动态的实现数据的读取及内表的赋值.

前文DB02 SQL编辑器SQL语句自动生成报表 就采用了ADBC访问数据库的方法: 根据语句动态定义选择屏幕,动态定义内表, 读取的数据写入内表呈现.

详见链接无峰,公众号:ABAP开发技巧SAP工具箱之一键生成报表

该工具在付费文章中可以获取.

文中通过AMDP方式连接外部数据库的验证失败. 不推荐使用. 其它三种方式根据实际情况选择使用就好.

示例代码详见文末.

示例代码,

*&---------------------------------------------------------------------*
*& Report ZTS_SQL_DBCO
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zts_dbco_opensql.PARAMETERS: p_s4  RADIOBUTTON GROUP ra1,p_ora RADIOBUTTON GROUP ra1.START-OF-SELECTION.CASE 'X'.WHEN p_s4.
*访问另一个S4系统的同名表
*需要注意的是,目标系统CLIENT和当前CLIENT 很可能不一样, 所以需要加上CLIENT SPECIFIED 避免CLIENT不同干扰数据获取SELECT * FROM usr02  CLIENT SPECIFIED  INTO  TABLE @DATA(lt_usr02)  BYPASSING BUFFER CONNECTION R/3*S4QWHERE bname = '00177'.."可以获取数据DATA(lv_subrc) = sy-subrc .cl_demo_output=>write( lv_subrc ).cl_demo_output=>write( lt_usr02 ).cl_demo_output=>display(  ).WHEN p_ora.
*访问另一个其它系统的同名表
*如果ABAP表有MANDT , 目标表没有, 则需要添加CLIENT SPECIFIED 避免系统自动添加MANDT 的限制条件,导致报错:字段MANDT不存在DATA: BEGIN OF ls_temp,zztno(30),werks(4),END OF ls_temp.DATA: lt_temp LIKE TABLE OF ls_temp.SELECT zztno,werks FROM zttemp CLIENT SPECIFIED CONNECTION mtdINTO TABLE @lt_temp.cl_demo_output=>display( lt_temp ).ENDCASE.
*  COMMIT CONNECTION s4q. "在连接中提交.

示例代码 NATIVESQL

*&---------------------------------------------------------------------*
*& Report ZTS_SQL_DBCO
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zts_dbco_nativesql.PARAMETERS:p_1 RADIOBUTTON GROUP ra1,p_2 RADIOBUTTON GROUP ra1,p_3 RADIOBUTTON GROUP ra1,p_4 RADIOBUTTON GROUP ra1.DATA: BEGIN OF gs_temp,zztno(30),werks(4),END OF gs_temp.
DATA: gt_temp LIKE TABLE OF gs_temp.
DATA conn TYPE dbcon-con_name.INITIALIZATION.%_p_1_%_app_%-text = 'SELECT方式一:DO循环读取游标,添加内表'.%_p_2_%_app_%-text = 'SELECT方式二:通过例程添加内表'.%_p_3_%_app_%-text = 'UPDATE:更新表内容'.%_p_4_%_app_%-text = 'INSERT:写入表内容'.START-OF-SELECTION.conn = 'MTD'."检查连接是否已经打开EXEC SQL.SET CONNECTION :connENDEXEC.IF sy-subrc <> 0. "如果连接没有打开, 打开连接EXEC SQL.CONNECT TO :connENDEXEC.ENDIF.*两种方式: 方式一性能好于方式二CASE 'X'.WHEN p_1.PERFORM frm_method_1. "SELECT方式一:DO循环读取游标,添加内表'.WHEN p_2.PERFORM frm_method_2. "SELECT方式二:通过例程添加内表'.when p_3.perform frm_update.when p_4.perform frm_insert.ENDCASE."关闭数据库连接EXEC SQL.DISCONNECT :CONNENDEXEC.*输出结果CASE 'X'.WHEN p_1 or p_2.cl_demo_output=>display( gt_temp ).ENDCASE.
*&---------------------------------------------------------------------*
*& Form FRM_METHOD_1
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM frm_method_1 .DATA: ls_temp LIKE gs_temp,lt_temp LIKE TABLE OF ls_temp."执行SQL语句:通过open dbcur打开游标EXEC SQL.OPEN dbcur FORSELECT zztno,werks FROM zttempENDEXEC."循环通过游标读取记录" 两种赋值方式:" 1.按字段顺序赋值,select 字段与 INTO 字段顺序必须一致"   FETCH NEXT dbcur INTO :ls_TEMP-ZZTNO,:LS_TEMP-WERKS" 2.按结构整体赋值:select 字段必须与结构字段顺序一致,且字段长度一致."   FETCH NEXT dbcur INTO :ls_TEMPDO.EXEC SQL.FETCH NEXT dbcur INTO :ls_TEMP-ZZTNO,:LS_TEMP-WERKSENDEXEC.IF sy-subrc <> 0.EXIT.ELSE.APPEND ls_temp TO lt_temp.ENDIF.ENDDO."关闭游标EXEC SQL.CLOSE dbcurENDEXEC.gt_temp[] = lt_temp[].
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_METHOD_2
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM frm_method_2 .conn = 'MTD'."检查连接是否已经打开EXEC SQL.SET CONNECTION :connENDEXEC.IF sy-subrc <> 0. "如果连接没有打开, 打开连接EXEC SQL.CONNECT TO :connENDEXEC.ENDIF.
*注意:工作区 gs_temp 内表 gt_temp 必须是全局变量EXEC SQL PERFORMING FRM_FILL_DATA.SELECT zztno,werks FROM zttemp INTO :GS_TEMPENDEXEC.ENDFORM.
FORM frm_fill_data.APPEND gs_temp TO gt_temp.ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_UPDATE
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM frm_update .DATA: lv_werks(4).lv_werks = '1002'.EXEC SQL.UPDATE ZTTEMP SET WERKS = :LV_WERKSWHERE WERKS = '1003'ENDEXEC.IF sy-subrc = 0.
*提交数据更新EXEC SQL.COMMIT WORKENDEXEC.DATA: lv_msg(50).lv_msg = '更新成功记录数:' && sy-dbcnt .cl_demo_output=>display(  lv_msg ).ELSE.cl_demo_output=>display( '更新失败' ).ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_INSERT
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM frm_insert .DATA: lv_werks(4).lv_werks = '1002'.EXEC SQL.INSERT INTO ZTTEMP VALUES ('4502',:LV_WERKS)ENDEXEC.IF sy-subrc = 0.
*提交数据更新EXEC SQL.COMMIT WORKENDEXEC.DATA: lv_msg(50).lv_msg = '写入成功记录数:' && sy-dbcnt .cl_demo_output=>display(  lv_msg ).ELSE.cl_demo_output=>display( '写入失败' ).ENDIF.
ENDFORM.

*&---------------------------------------------------------------------*
*& Report ZTS_DBCO_ADBC
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zts_dbco_adbc.DATA: BEGIN OF gs_temp,zztno(30),werks(4),END OF gs_temp.
DATA: gt_temp LIKE TABLE OF gs_temp.
DATA conn TYPE dbcon-con_name.
DATA: gv_sql TYPE string.START-OF-SELECTION.gv_sql = 'SELECT zztno,werks FROM zttemp'.PERFORM frm_get_data_adbc_simple.
*  PERFORM frm_get_data_adbc.cl_demo_output=>display( gt_temp ).
*&---------------------------------------------------------------------*
*& Form FRM_GET_DATA_ADBC
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& -->  p1        text
*& <--  p2        text
*&---------------------------------------------------------------------*
FORM frm_get_data_adbc .DATA: r_adbc_conn   TYPE REF TO  cl_sql_connection,r_adbc_query  TYPE REF TO  cl_sql_statement,r_metadata    TYPE REF TO  data,it_metadata   TYPE         adbc_rs_metadata_descr_tab,lv_len        TYPE         i,lv_off        TYPE         i,wa_metadata   LIKE LINE OF it_metadata,r_adbc_result TYPE REF TO  cl_sql_result_set,r_tabletype   TYPE REF TO  cl_abap_tabledescr,r_cxadbc      TYPE REF TO  cx_dba_adbc,r_cxsql       TYPE REF TO  cx_sql_exception,tabix_n(4)    TYPE n,column_names  TYPE HASHED TABLE OF adbc_name WITH UNIQUE KEY table_line.DATA:         lv_stmt_type      TYPE string.DATA:ex_structdescr TYPE REF TO  cl_abap_structdescr,ex_result_ref  TYPE REF TO data.
*获取sql语句的类型lv_stmt_type = cl_hdb_sql_executor=>get_statement_type( gv_sql ).
*创建默认数据库的链接对象r_adbc_conn    = cl_db6_con=>get_connection( 'MTD' ).
*创建一个查询对象r_adbc_query   = r_adbc_conn->create_statement( ).
*基于sql语句创建一个结果对象r_adbc_result  = r_adbc_query->execute_query( gv_sql  ).
*获取结果集合的字段名it_metadata = r_adbc_result->get_metadata( ).
*使用结果集合的字段信息,创建一个数据对象-结构r_metadata = r_adbc_result->get_struct_ref( md_tab = it_metadata   p_strict = abap_false ).
*创建一个数据对象-内表ex_structdescr ?= cl_abap_typedescr=>describe_by_data_ref( r_metadata ).r_tabletype     = cl_abap_tabledescr=>create( p_line_type  = ex_structdescrp_table_kind = cl_abap_tabledescr=>tablekind_std ).CREATE DATA ex_result_ref TYPE HANDLE r_tabletype.
*传递结果集一个数据对象-内表r_adbc_result->set_param_table( itab_ref = ex_result_ref ).
*获取数据内容r_adbc_result->next_package( EXPORTING upto = 100 ).
*关闭连接r_adbc_result->close( ).
*赋值数据到内表FIELD-SYMBOLS: <fs_itab> TYPE STANDARD TABLE.ASSIGN ex_result_ref->* TO <fs_itab>.MOVE-CORRESPONDING <fs_itab> TO gt_temp.
ENDFORM.FORM frm_get_data_adbc_simple .DATA: r_adbc_conn   TYPE REF TO  cl_sql_connection,r_adbc_query  TYPE REF TO  cl_sql_statement,r_metadata    TYPE REF TO  data,it_metadata   TYPE         adbc_rs_metadata_descr_tab,lv_len        TYPE         i,lv_off        TYPE         i,wa_metadata   LIKE LINE OF it_metadata,r_adbc_result TYPE REF TO  cl_sql_result_set,r_tabletype   TYPE REF TO  cl_abap_tabledescr,r_cxadbc      TYPE REF TO  cx_dba_adbc,r_cxsql       TYPE REF TO  cx_sql_exception,tabix_n(4)    TYPE n,column_names  TYPE HASHED TABLE OF adbc_name WITH UNIQUE KEY table_line.DATA:         lv_stmt_type      TYPE string.DATA:ex_structdescr TYPE REF TO  cl_abap_structdescr,ex_result_ref  TYPE REF TO data.*创建默认数据库的链接对象r_adbc_conn    = cl_db6_con=>get_connection( 'MTD' ).
*创建一个查询对象r_adbc_query   = r_adbc_conn->create_statement( ).
*基于sql语句创建一个结果对象r_adbc_result  = r_adbc_query->execute_query( gv_sql  ).*定义DATA: lr_ref LIKE REF TO gt_temp.CREATE DATA lr_ref .
*传递结果集一个数据对象-内表r_adbc_result->set_param_table( itab_ref = lr_ref ).
*获取数据内容r_adbc_result->next_package( EXPORTING upto = 100 ).
*关闭连接r_adbc_result->close( ).
*赋值数据到内表gt_temp = lr_ref->*.
ENDFORM.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/83045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink Table 数据类型 及Stream转Table实战 和 Flink假(模拟、mock)数据生成工具

列举的flink Table API的数据类型。并生成与这些类型匹配的数据。 同时比较了DataType或LoglicalType默认conversionClass与Flink Table API中规定的内部类型的conversionClass的异同。 一、添加maven pom依赖 用于生成假数据。 <dependency><groupId>net.datafa…

IDEA(2023)解决运行乱码问题

&#x1f607;作者介绍&#xff1a;一个有梦想、有理想、有目标的&#xff0c;且渴望能够学有所成的追梦人。 &#x1f386;学习格言&#xff1a;不读书的人,思想就会停止。——狄德罗 ⛪️个人主页&#xff1a;进入博主主页 &#x1f5fc;专栏系列&#xff1a;无 &#x1f33c…

【计算机组成原理】读书笔记第三期:内存和磁盘的关系

目录 写在开头 内存与磁盘的关系 基本关系 磁盘缓存 虚拟内存 节约内存的编程方法 通过DLL文件实现函数共有 通过调用_stdcall来降低文件程序的大小 磁盘的物理结构 结尾 写在开头 本文继续阅读总结《程序是怎样跑起来的》这本书&#xff08;作者&#xff1a;矢泽…

操作系统(5-7分)

内容概述 进程管理 进程的状态 前驱图 同步和互斥 PV操作&#xff08;难点&#xff09; PV操作由P操作原语和V操作原语组成&#xff08;原语是不可中断的过程&#xff09;&#xff0c;对信号量进行操作&#xff0c;具体定义如下&#xff1a; P&#xff08;S&#xff09;&#…

【Java】安装多个jdk版本

需求描述 win10系统上已经安装过jdk8&#xff0c;但因为要做某些实验&#xff0c;需要安装个jdk7 解决方法 安装过程 下载地址 https://www.oracle.com/java/technologies/downloads/archive/ 安装步骤 .exe文件安装步骤安装即可 遇到问题 问题1&#xff1a;配置环境变…

【计算机网络】——传输层

//图片取自王道&#xff0c;仅做交流学习 一、传输层提供的服务 物理层、数据链路层、网络层是通信子网。 传输层&#xff1a;它属于面向通信部分的最高层&#xff0c;同时也是用户功能的最低层 为应用层提供通信服务使用网络层的服务 网络层提供主机之间的逻辑通信。 1、传输…

SpringMVC之JSR303与拦截器

目录 一.JSR303 1.什么是JSR303 2.为什么使用JSR303 3.JSR303常用注解 4.快速入门 4.1导入Maven依赖 4.2 配置校验规则 4.3 对服务端数据添加进行校验 4.4 结果测试 二.拦截器 1.什么是拦截器 2.拦截器与过滤器 3.应用场景 4.基本拦截器配置 5 案例演示&#xff0…

区块链实验室(23) - FISCO中PBFT耗时与流量特征

前面的实验(区块链实验室(11) - PBFT耗时与流量特征)用仿真的PBFT观察耗时。现在用真实的Fisco网络再次观察其特征。同样地&#xff0c;用相同的网络&#xff0c;即100个节点构成的无标度网络。在每个节点上发起10次交易&#xff0c;记录每次交易的耗时。结果见下图所示。 前半…

Android12.0 系统限制上网系列之iptables用IOemNetd实现app上网黑名单的实现

1.前言 在12.0的系统rom定制化开发中,对于系统限制网络的使用,在system中netd网络这块的产品需要中,会要求设置屏蔽某个app上网的功能, liunx中iptables命令也是比较重要的,接下来就来在IOemNetd这块实现app上网黑名单的的相关功能,就是在 系统中只能不允许某个app上网,…

UVA-1343 旋转游戏 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 题目其实不难&#xff0c;但是耗费了我较多时间。 这种题关键就是在于找到约束条件&#xff0c;我在DFS的基础上&#xff0c;试了很多种策略&#xff1a; 1. 对3种数字&#xff0c;每种数字…

VSCode『SSH』连接服务器『GUI界面』传输

前言 最近需要使用实验室的服务器训练带有 GUI 画面的 AI 算法模型&#xff08;pygame&#xff09;&#xff0c;但是我是使用 SSH 连接的&#xff0c;不能很好的显示模型训练的效果画面&#xff0c;所以下面将会讲解如何实现 SSH 连接传输 Linux GUI 画面的 注&#xff1a;我们…

Postman —— HTTP请求基础组成部分

一般来说&#xff0c;所有的HTTP Request都有最基础的4个部分组成&#xff1a;URL、 Method、 Headers和body。 &#xff08;1&#xff09;Method 要选择Request的Method是很简单的&#xff0c;Postman支持所有的请求方式。 &#xff08;2&#xff09;URL 要组装一条Request…

华为HCIA(五)

Vlan id 在802.1Q中 高级ACL不能匹配用户名和源MAC 2.4G频段被分为14个交叠的&#xff0c;错列的20MHz信道&#xff0c;信道编码从1到14&#xff0c;邻近的信道之间存在一定的重叠范围 STA通过Probe获取SSID信息 Snmp报文 网络管理设备异常发生时会发送trap报文 D类地址是…

基于Java网络书店商城设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

亚马逊云科技 Amazon Lightsail :一种在云服务器上运行容器的简单方法

当向开发人员介绍亚马逊云科技云服务时&#xff0c;通常会花一点时间来介绍并演示 Amazon Lightsail 。它是迄今为止开始使用亚马逊云科技的最简单方法。使用它&#xff0c;您在几分钟内即可在自己的虚拟服务器上运行您的应用程序。而后增加了在 Amazon Lightsail 上部署基于容…

C语言字符函数和字符串函数(1)

大家好&#xff0c;我们又见面了&#xff0c;让大家久等了&#xff0c;我们今天就来学习字符函数和字符串函数。 在开启今天的学习之前呢&#xff0c;我来解决一下一些小伙伴平时找不到库函数使用的烦恼&#xff0c;因为我们cplusplus.com最新版本不能够查询函数&#xff0c;我…

【面试题精讲】Mysql如何实现乐观锁

❝ 有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top ❞ 首发博客地址 文章更新计划 系列文章地址 在 MySQL 中&#xff0c;可以通过使用乐观锁来实现并发控制&#xff0c;以避免数据冲突和并发更新问…

排查disabled问题之谷歌新版本特性

问题复现 最近我突然接手一个后台的bug&#xff0c;这个后台很久没有迭代更新了&#xff0c;我也不熟悉业务&#xff0c;所以只能看一下源码&#xff0c;问题很快就复现&#xff0c;测试的修复操作也很正确&#xff0c;就是因为渲染的input标签中存在disableddisabled’属性导…

单片机论文参考:1、基于单片机的电子琴

摘要 随着社会的发展进步&#xff0c;音乐逐渐成为我们生活中很重要的一部分&#xff0c;有人曾说喜欢音乐的人不会向恶。我们都会抽空欣赏世界名曲&#xff0c;作为对精神的洗礼。本论文设计一个基于单片机的简易电子琴。电子琴是现代电子科技与音乐结合的产物&#xff0c;是一…

英国留学生务必谨慎使用ChatGPT!!!

ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;是OpenAI研发的聊天机器人程序&#xff0c;于2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见的模式和统计规律…