The PA transfer structure (KEI1) — its assignment lines, the source cost elements and the value field assignments — read straight from the tables. HANA SQL for DB02/ST04 → SQL Editor.
Sections 1–2 were verified on the EWM system (client 700, transfer structure FI, controlling area CA10) on 2026-08-28. Sections 3–5 were added on 2026-08-31 and verified on an S/4HANA sandbox (client 100, transfer structure FI, controlling area 0001).
1. Assignment lines (TKB9C × TKB9D)
| Case | Assignment lines of a transfer structure (TKB9C × TKB9D) |
|---|
| What it does | TKB9C holds the assignment lines (ERZUO), TKB9D the line texts. FAKMG = 'X' corresponds to the Qty billed/delivered checkbox in KEI1. The output is the left-hand list of the KEI1 screen. |
| Watch out | The transfer structure header is TKB9A and its text is TKB9B. All TKB9* tables are client-dependent (they have MANDT). |
| Result | 3 rows — 010 Salary, 020 Depreciation, 030 IO Salary (same as the KEI1 screen) |
SELECT c.ERSCH, c.ERZUO, d.ZTEXT, c.FAKMG
FROM TKB9C c
LEFT JOIN TKB9D d
ON d.MANDT = c.MANDT
AND d.ERSCH = c.ERSCH
AND d.ERZUO = c.ERZUO
AND d.SPRAS = 'E'
WHERE c.MANDT = '700'
AND c.ERSCH = 'FI'
ORDER BY c.ERZUO;
2. Source and value field per line (TKB9G × TKB9F)
| Case | Source (cost element) + value field assignment (TKB9G × TKB9F) |
|---|
| What it does | TKB9G is the source: per controlling area (KOKRS) either a cost element group (SETNR) or a single value / range (VALMIN~VALMAX). TKB9F is the value field assignment: value field (WRTFLD) per operating concern (ERKRS). One line can feed a different value field in each operating concern. |
| Watch out | FVKZ is the fixed/variable indicator (1 = fixed, 3 = total). Without the KOKRS condition the standard sample controlling areas (0001, CA01, DE01, ...) show up as well. |
| Result | 5 rows — 010: cost element 5070 → OC10/VV030 and S001/VWGK; 020: 5080 → VV040 and VRPRS; 030: 8040 → VV030 (FVKZ = 1) |
SELECT c.ERZUO, d.ZTEXT, g.KOKRS, g.SETNR, g.VALMIN, g.VALMAX,
f.ERKRS, f.FVKZ, f.WRTFLD
FROM TKB9C c
LEFT JOIN TKB9D d
ON d.MANDT = c.MANDT AND d.ERSCH = c.ERSCH
AND d.ERZUO = c.ERZUO AND d.SPRAS = 'E'
LEFT JOIN TKB9G g
ON g.MANDT = c.MANDT AND g.ERSCH = c.ERSCH
AND g.ERZUO = c.ERZUO AND g.KOKRS = 'CA10'
LEFT JOIN TKB9F f
ON f.MANDT = c.MANDT AND f.ERSCH = c.ERSCH
AND f.ERZUO = c.ERZUO
WHERE c.MANDT = '700'
AND c.ERSCH = 'FI'
ORDER BY c.ERZUO, f.ERKRS;
3. ABAP SQL, fully expanded (one row = transfer structure × assignment × source × value field)
| Case | List of transfer structures (TKB9A × TKB9B) |
|---|
| What it does | TKB9A is the transfer structure header, TKB9B the language-dependent name. Same as the first-screen list of KEI1/KEI2. |
| Watch out | TKB9A has practically no fields besides ERSCH (only check flags). The name only appears when TKB9B is joined. |
| Result | 9 rows — A1 / BK / BP / CO / E1 / F1 / FI / K1 / Y1 (S/4HANA, measured 2026-08-31) |
SELECT a~ersch, b~stext
FROM tkb9a AS a
LEFT OUTER JOIN tkb9b AS b
ON b~ersch = a~ersch
AND b~spras = 'E'
ORDER BY a~ersch
INTO TABLE @DATA(lt_str).
| Case | Full expansion + text joins for the code values |
|---|
| What it does | One row = transfer structure × assignment × sending cost element (source) × value field. Joining TKB9G (source, KOKRS axis) and TKB9F (value field, ERKRS axis) together gives the cross product of the two axes. MWKZ (1 = value field / 2 = quantity field), FVKZ (1 = fixed / 2 = variable / 3 = total) and ABKAT (variance category) are resolved to domain texts through DD07T. |
| Watch out | The SUBCLASS of the cost element group name (SETHEADERT) is the chart of accounts (KTOPL), not the controlling area. Join via TKA01-KTOPL to get exactly one row (KOKRS 0001 → KTOPL INT). Without SUBCLASS the row count multiplies by the number of charts of accounts. |
| Watch out | Value field texts cannot be derived by a naming rule, because each value field has its own data element (VV500 → RKE2_VV500, KWABPR → RKESKWABPR). The query goes through the field definition of CE1<ERKRS> in DD03L and then reads DD04T. |
| Watch out | In the ADT Data Preview (SQL console) the request fails with HTTP 400 once the number of joins grows, so the whole query could not be run there. It was verified in pieces of 2–3 joins and then combined. Run it from SE16N, an ABAP report, or DB02 SQL. |
| Result | 13 rows — transfer structure FI / controlling area 0001 (S/4HANA, measured 2026-08-31) |
SELECT c~ersch AS transfer_str, bt~stext AS str_text,
c~erzuo AS assignment, dt~ztext AS asg_text,
g~kokrs AS co_area, ka~bezei AS co_area_text,
g~class AS set_class, g~setnr AS ce_group,
sh~descript AS ce_group_text,
g~valmin AS ce_from, g~valmax AS ce_to,
g~abkat AS var_categ, ab~ddtext AS var_categ_text,
f~erkrs AS op_concern,
f~wrtfld AS value_field, d4~ddtext AS value_field_text,
f~mwkz AS qty_val_ind, mw~ddtext AS qty_val_text,
f~fvkz AS fix_var_ind, fv~ddtext AS fix_var_text
FROM tkb9c AS c
LEFT OUTER JOIN tkb9b AS bt ON bt~ersch = c~ersch AND bt~spras = 'E'
LEFT OUTER JOIN tkb9d AS dt ON dt~ersch = c~ersch AND dt~erzuo = c~erzuo
AND dt~spras = 'E'
LEFT OUTER JOIN tkb9g AS g ON g~ersch = c~ersch AND g~erzuo = c~erzuo
LEFT OUTER JOIN tka01 AS ka ON ka~kokrs = g~kokrs
LEFT OUTER JOIN setheadert AS sh ON sh~setclass = g~class
AND sh~subclass = ka~ktopl
AND sh~setname = g~setnr
AND sh~langu = 'E'
LEFT OUTER JOIN dd07t AS ab ON ab~domname = 'ABKAT'
AND ab~domvalue_l = g~abkat
AND ab~ddlanguage = 'E'
LEFT OUTER JOIN tkb9f AS f ON f~ersch = c~ersch AND f~erzuo = c~erzuo
LEFT OUTER JOIN dd03l AS l ON l~tabname = concat( 'CE1', f~erkrs )
AND l~fieldname = f~wrtfld
LEFT OUTER JOIN dd04t AS d4 ON d4~rollname = l~rollname
AND d4~ddlanguage = 'E'
LEFT OUTER JOIN dd07t AS mw ON mw~domname = 'RKE_MWKZ2'
AND mw~domvalue_l = f~mwkz
AND mw~ddlanguage = 'E'
LEFT OUTER JOIN dd07t AS fv ON fv~domname = 'RKE_FVKZ'
AND fv~domvalue_l = f~fvkz
AND fv~ddlanguage = 'E'
WHERE c~ersch = 'FI'
AND g~kokrs = '0001'
ORDER BY c~ersch, c~erzuo, g~kokrs, f~erkrs, f~wrtfld
INTO TABLE @DATA(lt_out).
4. DB02/ST04 HANA SQL, fully expanded (HANA SQL version of section 3)
| Case | Full expansion in HANA SQL (DB02/ST04 SQL Editor) |
|---|
| What it does | Returns the same result as the ABAP SQL in section 3. The join structure is identical; only the notation differs. MANDT goes into the conditions and joins explicitly, ABAP SQL concat() becomes CONCAT(), and the DDIC text tables get AS4LOCAL = 'A' (active version). |
| Watch out | The CLASS column of TKB9G collides with a HANA reserved word and must be written as g."CLASS" in double quotes. |
| Watch out | DD03L / DD04T / DD07T are client-independent — do not add a MANDT join on them. |
| Watch out | SETHEADERT SUBCLASS is the chart of accounts (KTOPL). Join via TKA01-KTOPL to get one row. |
| Result | 13 rows — identical to the section 3 ABAP SQL result down to the values. Confirmed by running this SQL unchanged through ADBC (CL_SQL_STATEMENT) on S/4HANA client 100 (2026-08-31). |
SELECT c.ERSCH, bt.STEXT AS STR_TEXT,
c.ERZUO, dt.ZTEXT AS ASG_TEXT,
g.KOKRS, ka.BEZEI AS CO_AREA_TEXT,
g."CLASS", g.SETNR, sh.DESCRIPT AS CE_GROUP_TEXT,
g.VALMIN, g.VALMAX,
g.ABKAT, ab.DDTEXT AS VAR_CATEG_TEXT,
f.ERKRS, f.WRTFLD, d4.DDTEXT AS VALUE_FIELD_TEXT,
f.MWKZ, mw.DDTEXT AS QTY_VAL_TEXT,
f.FVKZ, fv.DDTEXT AS FIX_VAR_TEXT
FROM TKB9C c
LEFT JOIN TKB9B bt ON bt.MANDT=c.MANDT AND bt.ERSCH=c.ERSCH AND bt.SPRAS='E'
LEFT JOIN TKB9D dt ON dt.MANDT=c.MANDT AND dt.ERSCH=c.ERSCH
AND dt.ERZUO=c.ERZUO AND dt.SPRAS='E'
LEFT JOIN TKB9G g ON g.MANDT=c.MANDT AND g.ERSCH=c.ERSCH AND g.ERZUO=c.ERZUO
LEFT JOIN TKA01 ka ON ka.MANDT=c.MANDT AND ka.KOKRS=g.KOKRS
LEFT JOIN SETHEADERT sh ON sh.MANDT=c.MANDT AND sh.SETCLASS=g."CLASS"
AND sh.SUBCLASS=ka.KTOPL AND sh.SETNAME=g.SETNR
AND sh.LANGU='E'
LEFT JOIN DD07T ab ON ab.DOMNAME='ABKAT' AND ab.DOMVALUE_L=g.ABKAT
AND ab.DDLANGUAGE='E' AND ab.AS4LOCAL='A'
LEFT JOIN TKB9F f ON f.MANDT=c.MANDT AND f.ERSCH=c.ERSCH AND f.ERZUO=c.ERZUO
LEFT JOIN DD03L l ON l.TABNAME=CONCAT('CE1', f.ERKRS) AND l.FIELDNAME=f.WRTFLD
AND l.AS4LOCAL='A'
LEFT JOIN DD04T d4 ON d4.ROLLNAME=l.ROLLNAME AND d4.DDLANGUAGE='E'
AND d4.AS4LOCAL='A'
LEFT JOIN DD07T mw ON mw.DOMNAME='RKE_MWKZ2' AND mw.DOMVALUE_L=f.MWKZ
AND mw.DDLANGUAGE='E' AND mw.AS4LOCAL='A'
LEFT JOIN DD07T fv ON fv.DOMNAME='RKE_FVKZ' AND fv.DOMVALUE_L=f.FVKZ
AND fv.DDLANGUAGE='E' AND fv.AS4LOCAL='A'
WHERE c.MANDT = '100'
AND c.ERSCH = 'FI'
AND g.KOKRS = '0001'
ORDER BY c.ERZUO, f.ERKRS, f.WRTFLD;
5. When the source is a cost element group — expand to individual cost elements
| Case | Group → individual cost elements (SETNODE / SETLEAF / CSKB / SKAT) |
|---|
| What it does | SETNR in TKB9G only carries the group name, so the accounts actually covered are not visible. The group hierarchy is in SETNODE (child groups), the values in SETLEAF (VALFROM~VALTO ranges). Joining the ranges to CSKB (cost element master) keeps only cost elements that really exist, and SKAT adds the account name. |
| Watch out | HANA does not support WITH RECURSIVE (the run fails with "incorrect syntax near "grp""). The hierarchy is therefore unrolled level by level with UNION ALL; this query covers 3 levels (group → child → grandchild). For deeper groups add another UNION ALL block in the same pattern. |
| Watch out | Level 0 (the group itself) must also be part of the UNION ALL — there is no guarantee that leaves only sit at the lowest level. |
| Watch out | SUBCLASS in SETNODE / SETLEAF is the chart of accounts (KTOPL) as well; it is taken from TKA01-KTOPL. |
| Result | 169 rows — assignment 010 = 20 / 020 = 14 / 030 = 75 / 040 = 27 / 050 = 33 (S/4HANA client 100, run unchanged through ADBC, 2026-08-31) |
WITH sets (ersch, erzuo, kokrs, root_set, sc, sub, sn) AS (
-- level 0 : the group itself
SELECT g.ERSCH, g.ERZUO, g.KOKRS, g.SETNR, g."CLASS", ka.KTOPL, g.SETNR
FROM TKB9G g
INNER JOIN TKA01 ka ON ka.MANDT=g.MANDT AND ka.KOKRS=g.KOKRS
WHERE g.MANDT='100' AND g.ERSCH='FI' AND g.KOKRS='0001' AND g.SETNR<>''
UNION ALL
-- level 1 : child groups
SELECT g.ERSCH, g.ERZUO, g.KOKRS, g.SETNR, n1.SUBSETCLS, n1.SUBSETSCLS, n1.SUBSETNAME
FROM TKB9G g
INNER JOIN TKA01 ka ON ka.MANDT=g.MANDT AND ka.KOKRS=g.KOKRS
INNER JOIN SETNODE n1 ON n1.MANDT=g.MANDT AND n1.SETCLASS=g."CLASS"
AND n1.SUBCLASS=ka.KTOPL AND n1.SETNAME=g.SETNR
WHERE g.MANDT='100' AND g.ERSCH='FI' AND g.KOKRS='0001' AND g.SETNR<>''
UNION ALL
-- level 2 : grandchild groups
SELECT g.ERSCH, g.ERZUO, g.KOKRS, g.SETNR, n2.SUBSETCLS, n2.SUBSETSCLS, n2.SUBSETNAME
FROM TKB9G g
INNER JOIN TKA01 ka ON ka.MANDT=g.MANDT AND ka.KOKRS=g.KOKRS
INNER JOIN SETNODE n1 ON n1.MANDT=g.MANDT AND n1.SETCLASS=g."CLASS"
AND n1.SUBCLASS=ka.KTOPL AND n1.SETNAME=g.SETNR
INNER JOIN SETNODE n2 ON n2.MANDT=g.MANDT AND n2.SETCLASS=n1.SUBSETCLS
AND n2.SUBCLASS=n1.SUBSETSCLS AND n2.SETNAME=n1.SUBSETNAME
WHERE g.MANDT='100' AND g.ERSCH='FI' AND g.KOKRS='0001' AND g.SETNR<>''
)
SELECT s.ersch, s.erzuo, dt.ZTEXT AS ASG_TEXT, s.kokrs,
s.root_set, sh.DESCRIPT AS GROUP_TEXT, s.sn AS SUB_GROUP,
lf.VALFROM, lf.VALTO, ce.KSTAR, sk.TXT20 AS ACCOUNT_TEXT
FROM sets s
INNER JOIN SETLEAF lf ON lf.MANDT='100' AND lf.SETCLASS=s.sc
AND lf.SUBCLASS=s.sub AND lf.SETNAME=s.sn
INNER JOIN CSKB ce ON ce.MANDT='100' AND ce.KOKRS=s.kokrs
AND ce.KSTAR BETWEEN lf.VALFROM AND lf.VALTO
LEFT JOIN TKB9D dt ON dt.MANDT='100' AND dt.ERSCH=s.ersch
AND dt.ERZUO=s.erzuo AND dt.SPRAS='E'
LEFT JOIN SETHEADERT sh ON sh.MANDT='100' AND sh.SETCLASS='0102'
AND sh.SUBCLASS=s.sub AND sh.SETNAME=s.root_set
AND sh.LANGU='E'
LEFT JOIN SKAT sk ON sk.MANDT='100' AND sk.SPRAS='E'
AND sk.KTOPL=s.sub AND sk.SAKNR=ce.KSTAR
ORDER BY s.erzuo, ce.KSTAR;
| Case | Excerpt of the expansion — assignment 010 (Personnel costs) |
|---|
| What it does | Group INT-1 resolves through its child groups INT-1-1 / INT-1-2 / INT-1-3 into 20 individual cost elements. What section 4 showed as a single group name "INT-1" becomes the real account list. |
| Result | 20 rows (the assignment 010 part of the 169 rows) |
Comments
Post a Comment