如何仅使用一个 ABAP SQL 语句连接以下 3 个表
How to join the following 3 tables with exactly one ABAP SQL statement
我有以下 3 个数据表:
ZMYTABLE
列:ZUSER
& ZTCODE
和 2 条记录
elias VA01
elias VF01
AGR_1251
与记录
SD_role VA01
SD2_role VA01
SD3_role VA01
SD_role VA02
FI_role VF01
FI_role VF02
AGR_USERS
有记录
elias SD_role
elias SD2_role
maria SD_role
maria FI_role
我想显示字段 ZUSER
、ZTCODE
和 AGR_NAME
。
我想要来自 ZMYTABLE
的所有记录,其中存在特定用户的每个 tcode 的角色,即:
ZUSER---ZTCODE---AGRNAME
elias---VA01-----SD_role
elias---VA01-----SD2_role
elias---VF01-----
有人可以告诉我如何通过在 ABAP V7.01 sp07 中使用一个 ABAP SQL 语句连接 3 个表来做到这一点吗?
数据库访问应如下所示:
SELECT DISTINCT zmytable~zuser,
zmytable~ztcode,
agr_1251~agr_name
FROM zmytable
INNER JOIN agr_1251
ON agr_1251.ztcode EQ zmytable.ztcode
INNER JOIN agr_users
ON agr_users.zuser EQ zmytable.zuser
WHERE
agr_users.agr_name EQ agr_1251.agr_name OR EXISTS(
SELECT *
FROM agr_users AS inner_agr_users
INNER JOIN agr_1251 AS inner_agr_1251
ON inner_agr_1251.agr_name EQ inner_agr_users.agr_name
WHERE
inner_agr_users.agr_name EQ agr_1251.agr_name
).
添加INTO
子句并处理输出。
- 我打算有空的时候再升级一下解释的答案。
要访问所有记录,您应该使用如下的数据库访问。
SELECT b~zuser, b~ztcode, a~agr_name
FROM agr_1251 as a
INNER JOIN zmytable as b
ON a~tcode EQ b~tcode
INNER JOIN agr_user as c
ON a~agr_name EQ c~agr_name.
剩下的你可以使用ABAP来显示输出。
我发现使用 UNION
更容易,第一个 SELECT 将 return 对应于匹配用户角色之一的交易的行(elias,VA01,SD_role 和 SD2_role),第二个将 return 与不匹配任何用户角色(elias,VF01)的交易相对应的行。
我用 USR07 替换 ZMYTABLE 进行了测试。
SELECT usr07~bname, usr07~tcode, agr_1251~agr_name
FROM agr_users
INNER JOIN usr07
ON usr07~bname EQ agr_users~uname
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name
AND agr_1251~low EQ usr07~tcode
UNION
SELECT DISTINCT usr07~bname, usr07~tcode, ' ' AS agr_name
FROM usr07
WHERE NOT EXISTS (
SELECT * FROM agr_users
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name
WHERE usr07~bname EQ agr_users~uname
AND agr_1251~low EQ usr07~tcode )
INTO TABLE @DATA(result).
它给出了这些结果(针对 ABAP 单元格式化):
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = '' ) ) ).
下面是 ABAP 单元测试代码,用于证明它可以正常工作,如果需要,您可以尝试一下。您需要 ABAP 7.52(打开 SQL Test Double Framework)。
CLASS ltc_main DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS
INHERITING FROM cl_aunit_assert.
PRIVATE SECTION.
METHODS test FOR TESTING.
CLASS-METHODS: class_setup, class_teardown.
CLASS-DATA environment TYPE REF TO if_osql_test_environment.
ENDCLASS.
CLASS ltc_main IMPLEMENTATION.
METHOD class_setup.
environment = cl_osql_test_environment=>create( i_dependency_list = VALUE #(
( 'USR07' ) ( 'AGR_1251' ) ( 'AGR_USERS' ) ) ).
ENDMETHOD.
METHOD test.
TYPES ty_usr07 TYPE STANDARD TABLE OF usr07 WITH EMPTY KEY.
TYPES ty_agr_1251 TYPE STANDARD TABLE OF agr_1251 WITH EMPTY KEY.
TYPES ty_agr_users TYPE STANDARD TABLE OF agr_users WITH EMPTY KEY.
environment->insert_test_data( EXPORTING i_data = VALUE ty_usr07(
( bname = 'elias' tcode = 'VA01' timestamp = 1 )
( bname = 'elias' tcode = 'VF01' timestamp = 2 ) ) ).
environment->insert_test_data( EXPORTING i_data = VALUE ty_agr_1251(
( agr_name = 'SD_role' low = 'VA01' counter = 1 )
( agr_name = 'SD2_role' low = 'VA01' counter = 1 )
( agr_name = 'SD3_role' low = 'VA01' counter = 1 )
( agr_name = 'SD_role ' low = 'VA02' counter = 2 )
( agr_name = 'FI_role ' low = 'VF01' counter = 1 )
( agr_name = 'FI_role ' low = 'VF02' counter = 2 ) ) ).
environment->insert_test_data( EXPORTING i_data = VALUE ty_agr_users(
( uname = 'elias' agr_name = 'SD_role ' )
( uname = 'elias' agr_name = 'SD2_role' )
( uname = 'maria' agr_name = 'SD_role ' )
( uname = 'maria' agr_name = 'FI_role ' ) ) ).
"<==== here insert the ABAP SQL provided above & expectations to verify
ROLLBACK WORK.
ENDMETHOD.
METHOD class_teardown.
environment->destroy( ).
ENDMETHOD.
ENDCLASS.
如果您的 ABAP 版本 < 7.50,UNION
是不可能的,而是定义 2 个单独的 SELECT
,第一个 INTO TABLE @DATA(result)
,第二个 APPENDING TABLE result
.
PS: 我也做了以下测试,受其他答案的启发,它们不起作用(大多数return作用"FI_role" for "VF01",而不是空角色)。
尝试 1-A 失败:
SELECT usr07~bname, usr07~tcode, agr_1251~agr_name
FROM agr_users
INNER JOIN usr07
ON usr07~bname EQ agr_users~uname
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name AND
agr_1251~low EQ usr07~tcode
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' ) ) ).
尝试 1-B 失败:
SELECT DISTINCT usr07~bname,
usr07~tcode,
agr_1251~agr_name
FROM usr07
INNER JOIN agr_1251
ON agr_1251~low EQ usr07~tcode
INNER JOIN agr_users
ON agr_users~uname EQ usr07~bname
WHERE
agr_users~agr_name EQ agr_1251~agr_name OR EXISTS (
SELECT *
FROM agr_users AS inner_agr_users
INNER JOIN agr_1251 AS inner_agr_1251
ON inner_agr_1251~agr_name EQ inner_agr_users~agr_name
WHERE
inner_agr_users~agr_name EQ agr_1251~agr_name
)
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = 'FI_role' ) ) ).
失败的尝试 2:
SELECT b~bname, b~tcode, a~agr_name
FROM agr_1251 as a
INNER JOIN usr07 as b
ON a~low EQ b~tcode
INNER JOIN agr_users as c
ON a~agr_name EQ c~agr_name
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = 'FI_role' ) ) ).
Triple Join 适用于版本 > 7.4。
SELECT c~zuser, a~zrole, c~ztcode INTO CORRESPONDING FIELDS OF TABLE @lt_result
FROM agr_users AS a INNER JOIN agr_1251 AS b
ON a~zrole = b~zrole
RIGHT OUTER JOIN zmytable AS c
ON c~ztcode = b~ztcode AND c~zuser = a~zuser.
我有以下 3 个数据表:
ZMYTABLE
列:ZUSER
& ZTCODE
和 2 条记录
elias VA01
elias VF01
AGR_1251
与记录
SD_role VA01
SD2_role VA01
SD3_role VA01
SD_role VA02
FI_role VF01
FI_role VF02
AGR_USERS
有记录
elias SD_role
elias SD2_role
maria SD_role
maria FI_role
我想显示字段 ZUSER
、ZTCODE
和 AGR_NAME
。
我想要来自 ZMYTABLE
的所有记录,其中存在特定用户的每个 tcode 的角色,即:
ZUSER---ZTCODE---AGRNAME
elias---VA01-----SD_role
elias---VA01-----SD2_role
elias---VF01-----
有人可以告诉我如何通过在 ABAP V7.01 sp07 中使用一个 ABAP SQL 语句连接 3 个表来做到这一点吗?
数据库访问应如下所示:
SELECT DISTINCT zmytable~zuser,
zmytable~ztcode,
agr_1251~agr_name
FROM zmytable
INNER JOIN agr_1251
ON agr_1251.ztcode EQ zmytable.ztcode
INNER JOIN agr_users
ON agr_users.zuser EQ zmytable.zuser
WHERE
agr_users.agr_name EQ agr_1251.agr_name OR EXISTS(
SELECT *
FROM agr_users AS inner_agr_users
INNER JOIN agr_1251 AS inner_agr_1251
ON inner_agr_1251.agr_name EQ inner_agr_users.agr_name
WHERE
inner_agr_users.agr_name EQ agr_1251.agr_name
).
添加INTO
子句并处理输出。
- 我打算有空的时候再升级一下解释的答案。
要访问所有记录,您应该使用如下的数据库访问。
SELECT b~zuser, b~ztcode, a~agr_name
FROM agr_1251 as a
INNER JOIN zmytable as b
ON a~tcode EQ b~tcode
INNER JOIN agr_user as c
ON a~agr_name EQ c~agr_name.
剩下的你可以使用ABAP来显示输出。
我发现使用 UNION
更容易,第一个 SELECT 将 return 对应于匹配用户角色之一的交易的行(elias,VA01,SD_role 和 SD2_role),第二个将 return 与不匹配任何用户角色(elias,VF01)的交易相对应的行。
我用 USR07 替换 ZMYTABLE 进行了测试。
SELECT usr07~bname, usr07~tcode, agr_1251~agr_name
FROM agr_users
INNER JOIN usr07
ON usr07~bname EQ agr_users~uname
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name
AND agr_1251~low EQ usr07~tcode
UNION
SELECT DISTINCT usr07~bname, usr07~tcode, ' ' AS agr_name
FROM usr07
WHERE NOT EXISTS (
SELECT * FROM agr_users
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name
WHERE usr07~bname EQ agr_users~uname
AND agr_1251~low EQ usr07~tcode )
INTO TABLE @DATA(result).
它给出了这些结果(针对 ABAP 单元格式化):
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = '' ) ) ).
下面是 ABAP 单元测试代码,用于证明它可以正常工作,如果需要,您可以尝试一下。您需要 ABAP 7.52(打开 SQL Test Double Framework)。
CLASS ltc_main DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS
INHERITING FROM cl_aunit_assert.
PRIVATE SECTION.
METHODS test FOR TESTING.
CLASS-METHODS: class_setup, class_teardown.
CLASS-DATA environment TYPE REF TO if_osql_test_environment.
ENDCLASS.
CLASS ltc_main IMPLEMENTATION.
METHOD class_setup.
environment = cl_osql_test_environment=>create( i_dependency_list = VALUE #(
( 'USR07' ) ( 'AGR_1251' ) ( 'AGR_USERS' ) ) ).
ENDMETHOD.
METHOD test.
TYPES ty_usr07 TYPE STANDARD TABLE OF usr07 WITH EMPTY KEY.
TYPES ty_agr_1251 TYPE STANDARD TABLE OF agr_1251 WITH EMPTY KEY.
TYPES ty_agr_users TYPE STANDARD TABLE OF agr_users WITH EMPTY KEY.
environment->insert_test_data( EXPORTING i_data = VALUE ty_usr07(
( bname = 'elias' tcode = 'VA01' timestamp = 1 )
( bname = 'elias' tcode = 'VF01' timestamp = 2 ) ) ).
environment->insert_test_data( EXPORTING i_data = VALUE ty_agr_1251(
( agr_name = 'SD_role' low = 'VA01' counter = 1 )
( agr_name = 'SD2_role' low = 'VA01' counter = 1 )
( agr_name = 'SD3_role' low = 'VA01' counter = 1 )
( agr_name = 'SD_role ' low = 'VA02' counter = 2 )
( agr_name = 'FI_role ' low = 'VF01' counter = 1 )
( agr_name = 'FI_role ' low = 'VF02' counter = 2 ) ) ).
environment->insert_test_data( EXPORTING i_data = VALUE ty_agr_users(
( uname = 'elias' agr_name = 'SD_role ' )
( uname = 'elias' agr_name = 'SD2_role' )
( uname = 'maria' agr_name = 'SD_role ' )
( uname = 'maria' agr_name = 'FI_role ' ) ) ).
"<==== here insert the ABAP SQL provided above & expectations to verify
ROLLBACK WORK.
ENDMETHOD.
METHOD class_teardown.
environment->destroy( ).
ENDMETHOD.
ENDCLASS.
如果您的 ABAP 版本 < 7.50,UNION
是不可能的,而是定义 2 个单独的 SELECT
,第一个 INTO TABLE @DATA(result)
,第二个 APPENDING TABLE result
.
PS: 我也做了以下测试,受其他答案的启发,它们不起作用(大多数return作用"FI_role" for "VF01",而不是空角色)。
尝试 1-A 失败:
SELECT usr07~bname, usr07~tcode, agr_1251~agr_name
FROM agr_users
INNER JOIN usr07
ON usr07~bname EQ agr_users~uname
INNER JOIN agr_1251
ON agr_1251~agr_name EQ agr_users~agr_name AND
agr_1251~low EQ usr07~tcode
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' ) ) ).
尝试 1-B 失败:
SELECT DISTINCT usr07~bname,
usr07~tcode,
agr_1251~agr_name
FROM usr07
INNER JOIN agr_1251
ON agr_1251~low EQ usr07~tcode
INNER JOIN agr_users
ON agr_users~uname EQ usr07~bname
WHERE
agr_users~agr_name EQ agr_1251~agr_name OR EXISTS (
SELECT *
FROM agr_users AS inner_agr_users
INNER JOIN agr_1251 AS inner_agr_1251
ON inner_agr_1251~agr_name EQ inner_agr_users~agr_name
WHERE
inner_agr_users~agr_name EQ agr_1251~agr_name
)
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = 'FI_role' ) ) ).
失败的尝试 2:
SELECT b~bname, b~tcode, a~agr_name
FROM agr_1251 as a
INNER JOIN usr07 as b
ON a~low EQ b~tcode
INNER JOIN agr_users as c
ON a~agr_name EQ c~agr_name
INTO TABLE @DATA(result).
SORT result BY bname tcode agr_name.
TYPES ty_result LIKE result.
assert_equals( act = result exp = VALUE ty_result(
( bname = 'elias' tcode = 'VA01' agr_name = 'SD2_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VA01' agr_name = 'SD_role' )
( bname = 'elias' tcode = 'VF01' agr_name = 'FI_role' ) ) ).
Triple Join 适用于版本 > 7.4。
SELECT c~zuser, a~zrole, c~ztcode INTO CORRESPONDING FIELDS OF TABLE @lt_result
FROM agr_users AS a INNER JOIN agr_1251 AS b
ON a~zrole = b~zrole
RIGHT OUTER JOIN zmytable AS c
ON c~ztcode = b~ztcode AND c~zuser = a~zuser.