ABAP SELECT Patterns on S/4HANA — Real Queries from Working Reports
SELECT queries actually used in our custom Z reports, organized by use case. The code is taken verbatim from working sources. New cases are added whenever a new program is built.
Each entry: Case / Explanation (+pitfalls) / The actual query. Last updated: 2026-08-13
CO — Standard Cost / Actuals — from ZCO0020 (standard cost vs actual)
▷ Standard cost header — latest released estimate (KEKO) — The latest released (FREIG='X') standard cost estimate (KALKA='01') by costing date (KADKY). SELECT SINGLE does not allow ORDER BY, so use UP TO 1 ROWS + ORDER BY instead
SELECT kalnr, kalka, kadky, tvers, bwvar, losgr, meins
FROM keko
WHERE matnr = @iv_matnr
AND werks = @p_werks
AND kalka = '01'
AND tvers = '01'
AND freig = 'X'
ORDER BY kadky DESCENDING
INTO @DATA(ls_keko)
UP TO 1 ROWS.
ENDSELECT.
▷ Standard cost itemization (CKIS) — Explode the input lines using the estimate header keys (KALNR/KALKA/KADKY/TVERS/BWVAR). TYPPS: M = material, E = activity, I = other (e.g. subcontracting purchase price)
SELECT typps, kstar, matnr, kostl, lstar, menge, meeht, wertn
FROM ckis
WHERE kalnr = @ls_keko-kalnr
AND kalka = @ls_keko-kalka
AND kadky = @ls_keko-kadky
AND tvers = @ls_keko-tvers
AND bwvar = @ls_keko-bwvar
ORDER BY posnr
INTO TABLE @DATA(lt_ckis).
▷ Production order consumption actuals (MSEG, FOR ALL ENTRIES) — Aggregate period consumption (261/262) and subcontracting components (543/544) for a list of production orders. FOR ALL ENTRIES silently removes fully duplicate rows, so the document key (MBLNR/MJAHR/ZEILE) MUST be in the SELECT list — otherwise identical lines from different documents collapse into one and totals go wrong (this is exactly why our subcontracting actuals once showed zero)
SELECT mblnr, mjahr, zeile, bwart, matnr, menge, meins, dmbtr
FROM mseg
FOR ALL ENTRIES IN @lt_aufnr
WHERE aufnr = @lt_aufnr-aufnr
AND bwart IN ('261','262','543','544')
AND budat_mkpf BETWEEN @gv_dat_from AND @gv_dat_to
INTO TABLE @DATA(lt_mseg).
▷ Goods receipt actuals for a product (MSEG) — 101/102 by material + plant — covers both production GRs and subcontracting (purchase order) GRs. 102 offsets with a -1 sign
SELECT mblnr, mjahr, bwart, menge, dmbtr, ebeln
FROM mseg
WHERE matnr = @iv_matnr
AND werks = @p_werks
AND bwart IN ('101','102')
AND budat_mkpf BETWEEN @gv_dat_from AND @gv_dat_to
INTO TABLE @DATA(lt_gr).
▷ Subcontracting processing fees (ACDOCA, KTOSL='FRL') — Subcontracting fees are stored in ACDOCA with account determination key FRL together with the parent material (MATNR) — sum directly by material + period
SELECT racct, hsl
FROM acdoca
WHERE rldnr = '0L'
AND rbukrs = @p_bukrs
AND ktosl = 'FRL'
AND matnr = @iv_matnr
AND budat BETWEEN @gv_dat_from AND @gv_dat_to
INTO TABLE @DATA(lt_frl).
▷ Activity actuals on production orders (ACDOCA) — Activity lines allocated to orders — on the receiver side LSTAR is empty and only the sender cost center (SCNTR) is filled, so identify them with SCNTR <> '' and match by cost element (RACCT)
SELECT belnr, docln, racct, scntr, msl, runit, hsl
FROM acdoca
FOR ALL ENTRIES IN @lt_aufnr
WHERE rldnr = '0L'
AND rbukrs = @p_bukrs
AND aufnr = @lt_aufnr-aufnr
AND scntr <> ''
AND budat BETWEEN @gv_dat_from AND @gv_dat_to
INTO TABLE @DATA(lt_activity).
CO — CO-PA / Allocation Cycles — from ZCO0030 · ZCO0041
▷ CO-PA line items — dynamic table name (CE1xxxx) — The table differs per operating concern (CE1OC10 / CE1JNC2), so SELECT with the table name in a variable. A PALEDGER='01' filter is mandatory — without it both valuation ledgers (01/02) come back and everything doubles. VRGAR='F' = actuals (billing-based)
SELECT bukrs, gjahr, perde, budat, kndnr, artnr, werks, vkorg, vtweg, spart,
absmg, absmg_me, vv010, vv020, vv021, vv022, vv023, vv030, vv040, vv090,
rec_waers, rbeln, rposn
FROM (gv_ce1tab)
WHERE bukrs = @p_bukrs
AND gjahr = @lv_gjahr
AND perde = @lv_perde
AND vrgar = 'F'
AND paledger = '01'
AND werks IN @s_werks
AND kndnr IN @s_kndnr
AND artnr IN @s_artnr
INTO CORRESPONDING FIELDS OF TABLE @lt_ce1.
▷ Distribution cycles + segments (T811C ⨝ T811S) — Cycle headers and segments in one shot — ALART='V' (distribution), TAB='CCSS' (classic CO-OM). SRULE/RRULE/SPERCENT/RCDATA/NEGTEST hold the segment rules
SELECT c~cycle, c~sdate, c~edate,
s~seqnr, s~name AS segname, s~srule, s~rrule, s~spercent,
s~rcdata, s~negtest
FROM t811c AS c
INNER JOIN t811s AS s
ON s~tab = c~tab
AND s~cycle = c~cycle
AND s~sdate = c~sdate
WHERE c~tab = @gc_tab
AND c~alart = 'V'
AND c~sdate IN @s_sdate
ORDER BY c~cycle, c~sdate, s~seqnr
INTO CORRESPONDING FIELDS OF TABLE @gt_seg.
▷ Cycle → controlling area link (T811K SEQNR='0000') — T811C has no KOKRS field — the controlling area sits in the cycle-level selection criteria (T811K SEQNR='0000', FIELD='KOKRS') as VALMIN. Used for F4 helps and filters
SELECT k~valmin AS kokrs, c~cycle, c~sdate, l~txt
FROM t811c AS c
INNER JOIN t811k AS k
ON k~tab = c~tab
AND k~cycle = c~cycle
AND k~sdate = c~sdate
AND k~seqnr = '0000'
AND k~field = 'KOKRS'
LEFT OUTER JOIN t811l AS l
ON l~tab = c~tab
AND l~cycle = c~cycle
AND l~sdate = c~sdate ...
▷ Segment criteria / receiver factors (T811K, T811F) — T811K criteria per SETKIND (0=cycle, 1=sender control, 2=sender, 3=receiver, 4=allocation base) and T811F receiver values per SRFLAG ('R'=portion/%, 'W'=weighting factor). Both use FOR ALL ENTRIES on the segment list
SELECT * FROM t811k
FOR ALL ENTRIES IN @gt_seg
WHERE tab = @gc_tab
AND cycle = @gt_seg-cycle
AND sdate = @gt_seg-sdate
INTO TABLE @gt_key.
SELECT * FROM t811f
FOR ALL ENTRIES IN @gt_seg
WHERE tab = @gc_tab
AND cycle = @gt_seg-cycle
AND sdate = @gt_seg-sdate
INTO TABLE @gt_fac.
FI — Financial Statements / Line Items — from ZFI0030 · ZFI0040
▷ P&L / BS balance aggregation (ACDOCA GROUP BY) — Period totals by account (RACCT) + functional area (RFAREA) — matched against the FSV item account ranges to build the financial statement tree. Note HSL stores credits (revenue) as negative
SELECT racct, rfarea, SUM( hsl ) AS amt
FROM acdoca
WHERE rldnr = @p_rldnr
AND rbukrs = @p_bukrs
AND gjahr = @p_gjahr
AND poper BETWEEN @p_perf AND @p_pert
GROUP BY racct, rfarea
INTO TABLE @DATA(lt_rpt).
▷ G/L open items (BSIS_VIEW) — In S/4HANA a direct reference to BSIS is a syntax error — SELECT from the compatibility view BSIS_VIEW (cleared items: BSAS_VIEW). CDS views cannot anchor SELECT-OPTIONS though, so anchor them on SKB1/BKPF
SELECT bukrs, hkont, belnr, buzei, gjahr, blart, budat, bldat,
shkzg, dmbtr, waers, zuonr, sgtxt
FROM bsis_view
WHERE hkont IN @s_hkont
AND bukrs IN @s_bukrs
AND budat IN @s_budat
AND blart IN @s_blart
INTO TABLE @DATA(lt_open).
Logistics — SD / MM — from ZSD0010 · ZMM0030 · ZCO0020
▷ Sales order list — header + item + customer name join (VBAK ⨝ VBAP) — S/4HANA removed the status tables (VBUK/VBUP), so status fields are read directly from VBAP — LFSTA (delivery) / FKSAA (billing) / GBSTA (overall). Customer name via LEFT OUTER JOIN to KNA1
SELECT a~vbeln, b~posnr, a~auart, a~vkorg, a~vtweg, a~spart,
a~kunnr, c~name1, a~erdat, a~audat,
b~matnr, b~arktx, b~werks, b~kwmeng, b~vrkme,
b~netwr, a~waerk,
b~lfsta, b~fksaa, b~gbsta, b~abgru
FROM vbak AS a
INNER JOIN vbap AS b
ON b~vbeln = a~vbeln
LEFT OUTER JOIN kna1 AS c
ON c~kunnr = a~kunnr
WHERE a~vbeln IN @s_vbeln
AND a~vkorg IN @s_vkorg
...
ORDER BY a~vbeln, b~posnr
INTO CORRESPONDING FIELDS OF TABLE @gt_list.
▷ Has the PO been invoiced? (EKBE history, FOR ALL ENTRIES) — EKPO-EREKZ (final invoice flag) stays off for partial invoices, so it must not be used for this — judge by the existence of VGABE='2' (invoice receipt) lines in the PO history. GROUP BY is not allowed with FOR ALL ENTRIES, so dedupe with SORT + DELETE ADJACENT DUPLICATES
SELECT ebeln, ebelp
FROM ekbe
FOR ALL ENTRIES IN @gt_list
WHERE ebeln = @gt_list-ebeln
AND ebelp = @gt_list-ebelp
AND vgabe = '2'
INTO TABLE @DATA(lt_inv).
SORT lt_inv BY ebeln ebelp.
DELETE ADJACENT DUPLICATES FROM lt_inv COMPARING ebeln ebelp.
▷ Material list — three-way master join (MARC ⨝ MARA + MAKT) — Semi-finished/finished goods existing in a plant, with names — the basic pattern of starting from the plant view (MARC) and joining general data (MARA) and names (MAKT)
SELECT a~matnr, a~mtart, k~maktx
FROM marc AS c
INNER JOIN mara AS a ON a~matnr = c~matnr
LEFT OUTER JOIN makt AS k ON k~matnr = a~matnr AND k~spras = @sy-langu
WHERE c~werks = @p_werks
AND a~mtart IN ('FERT','HALB')
AND a~matnr IN @s_matnr
ORDER BY a~matnr
INTO TABLE @DATA(lt_mat).
· How Sarah Joined a K-Dumpling Company and Became an SAP Genius — the business novel, 53 pages, $25
· The Dumpling Factory: Building a Complete SAP S/4HANA Company from Scratch — the build manual, 85 pages, $50
Comments
Post a Comment