原文:Small Fire · ABAP Native SQL · ABAP 子专栏 · Small Fire 技术笔记

Native SQL

EXEC SQL 和 ADBC 是所谓的 Native SQL,这种方式直接进入指定数据库,不涉及到 DBI,这样就没有 Table buffer。相对 EXEC SQL 来说,更推荐 ADBC 的方式执行 native sql,这种方式的好处是更加容易追踪错误。

连接其他的数据库 :TCode : DBCO

存储数据表:DBCON

添加新的连接:MSSQL_SERVER=IP adress MSSQL_DBNAME=dbname OBJECT_SOURCE=dbname

注意事项:

  • Native SQL 语句不能有结尾符号
  • EXEC SQL … ENDEXEC间不能有注释
  • 参数占位符是冒号:para_value

程序调用

连接DB

DATA: CON_NAME LIKE DBCON-CON_NAME VALUE 'DBNAME',
DATA: sql_error TYPE REF TO cx_sy_native_sql_error,
      error_text TYPE string.
...
 内表数据准备
...
" 连接数据库 "
TRY.
  EXEC SQL.
    CONNECT TO :CON_NAME
  ENDEXEC.
  EXEC SQL.
    SET CONNECTION 'CON_NAME'
  ENDEXEC.
  IF SY-SUBRC NE 0.
    error_text = 'Open Database Connection Error'.
    STOP.
  ENDIF.
ENDTRY.

查询语句

"执行SQL"
LOOP demo_datas.
  TRY.
    EXEC SQL PERFORMING frm_download_data.
      SELECT * into :wa_emp FROM emp
            WHERE index = :demo_datas-index
    ENDEXEC.
    CATCH CX_SY_NATIVE_SQL_ERROR.
      CLEAR: e_type,e_message.
      E_TYPE = 'E'.
      E_MESSAGE = 'Download RQM data Error'.
      CLEAR: wa_emp.
  ENDTRY.
ENDLOOP.

插入语句

TRY.
 LOOP AT gt_room INTO gs_room.
  EXEC SQL.
   insert into ljc_room ( room_id, room_name, room_people, room_desc )
   values(:gs_room-room_id, :gs_room-room_name, :gs_room-room_people, :gs_room-room_desc)
  ENDEXEC.
 ENDLOOP.
CATCH cx_sy_native_sql_error INTO sql_error.
 error_text = l_sql_error->get_text( ).
ENDTRY.

异常处理和连接断开

"异常处理"
IF error_text IS INITIAL.
 EXEC SQL.
  commit
 ENDEXEC.
ELSE.
 CLEAR error_text.
 EXEC SQL.
  rollback
 ENDEXEC.
ENDIF.
"断开连接"
EXEC SQL.
 DISCONNECT :p_dbname
ENDEXEC.

游标使用

DATA : arg1 TYPE string VALUE '800' .
TABLES : t001 .
EXEC SQL .
  OPEN c1 FOR  " 打开游标 "
  SELECT MANDT , BUKRS
	FROM T001      " 远程数据库表 "
    WHERE MANDT = :arg1 AND BUKRS >= 'ZA01'
ENDEXEC .
DO .
  EXEC SQL .
    FETCH NEXT c1 INTO :t001-mandt, :t001-bukrs  "读取游标"
  ENDEXEC .
  IF sy - subrc <> 0 .
    EXIT .
  ELSE .
    WRITE : / t001-mandt, t001-bukrs .
  ENDIF .
ENDDO .
EXEC SQL .
  CLOSE c1 "关闭游标"
ENDEXEC .

使用类调用 Native SQL

程序实例

REPORT z_sql_demo.
DATA: index TYPE i.
DATA: sql(100) TYPE c.
DATA: retcode  TYPE i.
TYPES: BEGIN OF sql_data,
	sql(300) TYPE c,
END OF sql_data.
DATA: sql_datas TYPE STANDARD TABLE OF sql_data WITH HEADER LINE.
"get datas"
"excute data"
LOOP AT datas.
  index = sy-tabix.
  CLEAR: sql.
  CLEAR: sql_datas, sql_datas[].
  CONCATENATE 'INSERT INTO table(id,para1,para2,para3,para4)' 'values('
         INTO sql SEPARATED BY space.
  CONDENSE sql.
  CONCATENATE sql
    '''' index ''''        ','
    '1'                    ','
    '''' datas-para2 ''''  ','
    '''' datas-para3 ''''  ','
    '''' datas-para4 ''''
    ')' INTO sql_datas-sql .
  APPEND sql_datas.
  CLEAR: retcode.
  CALL FUNCTION 'ZUU_EXEC_SQL'
    EXPORTING
      dbconn = 'CONN_NAME'
    IMPORTING
      result = retcode
    TABLES
      sql    = sql_datas.
  IF retcode = 0.
    "SQL Excute Success"
  ENDIF.
ENDLOOP.

子程序:ZUU_EXEC_SQL

FUNCTION ZUU_EXEC_SQL .
*"-------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(DBCONN) TYPE  C
*"  EXPORTING
*"     REFERENCE(RESULT) TYPE  I
*"  TABLES
*"      SQL
*"---------------------------------------------------------------
  TYPES: BEGIN OF t_sp_test,
    a TYPE char10,
  END OF t_sp_test,
  t_sp_test_tab TYPE TABLE OF t_sp_test.
  DATA: lt_sp_test TYPE t_sp_test_tab,
        ls_sp_test TYPE t_sp_test.
  DATA: lv_root_message TYPE string.
  DATA: lv_sql_message TYPE string.
  DATA: lv_param_message TYPE string.
  DATA: lr_cxsql TYPE REF TO cx_sql_exception.
  DATA: lr_cxpar TYPE REF TO cx_parameter_invalid.
  DATA: l_con_ref TYPE REF TO cl_sql_connection.
  DATA: l_stmt_ref TYPE REF TO cl_sql_statement.
  DATA: l_res_ref TYPE REF TO cl_sql_result_set.
  DATA: lv_stmt TYPE string.
  DATA: l_dref TYPE REF TO DATA,
        ncount TYPE I.
  TRY.
    CALL METHOD cl_sql_connection=>get_connection
      EXPORTING
        con_name = DBCONN
      RECEIVING
        con_ref = l_con_ref.
  CATCH cx_sql_exception INTO lr_cxsql.
    lv_root_message = lr_cxsql->get_text( ).
    lv_sql_message = lr_cxsql->sql_message.
    WRITE: / lv_root_message, / lv_sql_message.
  ENDTRY.
  result = 0.
  LOOP AT sql INTO lv_stmt.
    CALL METHOD l_con_ref->create_statement
      RECEIVING
        stmt_ref = l_stmt_ref.
    TRY.
      CALL METHOD l_stmt_ref->execute_update
        EXPORTING
          statement = lv_stmt
        receiving
          ROWS_PROCESSED = ncount.
    CATCH cx_sql_exception INTO lr_cxsql.
      result = 1.
      lv_root_message = lr_cxsql->get_text( ).
      lv_sql_message = lr_cxsql->sql_message.
      WRITE: / lv_root_message, / lv_sql_message.
      MESSAGE lv_stmt TYPE 'I'.
      EXIT.
    CATCH cx_parameter_invalid INTO lr_cxpar.
      result = 1.
      lv_root_message = lr_cxpar->get_text( ).
      lv_param_message = lr_cxpar->parameter.
      WRITE: / lv_root_message, / lv_param_message.
      EXIT.
    ENDTRY.
  ENDLOOP.
  IF result = 1.
    CALL METHOD l_con_ref->ROLLBACK.
  ELSE.
    CALL METHOD l_con_ref->COMMIT.
  ENDIF.
  GET REFERENCE OF ls_sp_test INTO l_dref.
  IF DBCONN <> 'DEFAULT'.
    CALL METHOD l_con_ref->CLOSE.
  ENDIF.
ENDFUNCTION.