SQL

BKPF BSEG Join: Keys, S/4HANA Changes and ACDOCA

Join SAP BKPF to BSEG on MANDT, BUKRS, BELNR and GJAHR, sign amounts with SHKZG, why BSEG was a cluster table, and when to read ACDOCA in S/4HANA instead.

On this page

To join BKPF to BSEG, match all four header keys, MANDT, BUKRS, BELNR and GJAHR; BSEG adds BUZEI as the line number, so one header fans out to its line items and nothing else. BKPF is the accounting document header, BSEG the accounting document segment (the lines), and that shape is the same in SAP ECC and S/4HANA. What changed is everything around it: in ECC, BSEG was a cluster table that ABAP could not join or aggregate, and in S/4HANA the reporting job moved to ACDOCA, the universal journal, while BSEG stayed on as the entry view. This page is the reference for all three: the join, why it used to be awkward, and when to stop using it.

The tables and their keys

TableWhat it holdsKeyOne row per
BKPFAccounting document headerMANDT, BUKRS, BELNR, GJAHRDocument
BSEGAccounting document segment: the entry-view line itemsMANDT, BUKRS, BELNR, GJAHR, BUZEIDocument line
ACDOCAUniversal journal (S/4HANA): the ledger-view line itemsRCLNT, RLDNR, RBUKRS, GJAHR, BELNR, DOCLNDocument line per ledger

A document is unique only across all four header fields. Leaving out BUKRS or GJAHR is the classic mistake: BELNR repeats across company codes and fiscal years, so a two-field join silently multiplies rows.

The fields you reach for most:

TableFieldMeaning
BKPFBLARTDocument type
BKPFBUDAT, BLDATPosting date, document date
BKPFXBLNRReference (often the external document number)
BKPFUSNAMUser who entered the document
BSEGBUZEILine item number, three digits, so at most 999 lines per document
BSEGKOARTAccount type: S G/L, D customer, K vendor, A asset, M material
BSEGHKONTG/L account
BSEGSHKZGDebit/credit indicator: S debit, H credit
BSEGDMBTR, WRBTRAmount in local currency, amount in document currency, both unsigned
BSEGAUGBL, AUGDTClearing document and clearing date

The join

Header joined to line items on the full key โ€” illustrative
SELECT
  h.bukrs,
  h.belnr,
  h.gjahr,
  h.blart,   -- document type
  h.budat,   -- posting date
  l.buzei,   -- line item number
  l.koart,   -- account type
  l.hkont,   -- G/L account
  l.shkzg,   -- debit/credit indicator (S/H)
  l.dmbtr    -- amount in local currency, unsigned
FROM bkpf AS h
JOIN bseg AS l
  ON  l.mandt = h.mandt
  AND l.bukrs = h.bukrs
  AND l.belnr = h.belnr
  AND l.gjahr = h.gjahr
WHERE h.mandt = '100'
  AND h.bukrs = '1000'
  AND h.gjahr = '2026'
ORDER BY h.belnr, l.buzei;

This is plain SQL of the kind you would run against a replicated copy or an S/4HANA system. Treat client, company code and year as placeholders.

Amounts are unsigned: read SHKZG

DMBTR and WRBTR are always positive. The direction lives in SHKZG (S = debit, H = credit), so summing DMBTR directly gives gross turnover, not a net balance.

Signed balance per G/L account โ€” illustrative
SELECT
  l.hkont,
  SUM(CASE WHEN l.shkzg = 'H' THEN -l.dmbtr ELSE l.dmbtr END) AS net_local
FROM bkpf AS h
JOIN bseg AS l
  ON  l.mandt = h.mandt
  AND l.bukrs = h.bukrs
  AND l.belnr = h.belnr
  AND l.gjahr = h.gjahr
WHERE h.mandt = '100'
  AND h.bukrs = '1000'
  AND h.gjahr = '2026'
GROUP BY l.hkont;

Why BSEG was awkward in ECC: a cluster table

In classic SAP ERP, BSEG is not an ordinary database table. It is a cluster table, physically stored inside the table cluster RFBLG, which is keyed on the document header fields. The ABAP Keyword Documentation lists what that costs in Open SQL: no joins with pooled or cluster tables, no GROUP BY or HAVING, and no column comparisons on the right side of a WHERE condition. Both SQL blocks above are therefore impossible as Open SQL on a classic ECC database.

SAP's answer was redundancy. The secondary index tables duplicate a subset of BSEG in transparent tables you can join and index: BSIS/BSAS for G/L items, BSID/BSAD for customers, BSIK/BSAK for vendors, with I for open and A for cleared items. Line-item reports such as FBL3N, FBL5N and FBL1N read those, not BSEG.

The idiomatic ECC pattern in ABAP is header first, lines second, with the full key:

Header first, then lines by full key โ€” illustrative ECC ABAP
SELECT bukrs, belnr, gjahr, blart, budat
  FROM bkpf
  WHERE bukrs = @lv_bukrs
    AND gjahr = @lv_gjahr
    AND blart = 'SA'
  INTO TABLE @DATA(lt_head).

IF lt_head IS NOT INITIAL.
  SELECT bukrs, belnr, gjahr, buzei, hkont, shkzg, dmbtr
    FROM bseg
    FOR ALL ENTRIES IN @lt_head
    WHERE bukrs = @lt_head-bukrs
      AND belnr = @lt_head-belnr
      AND gjahr = @lt_head-gjahr
    INTO TABLE @DATA(lt_items).
ENDIF.

(The inline-declaration syntax needs a recent ABAP release; on an older ECC the same logic uses classic SELECT ... INTO TABLE with declared internal tables.)

ECC on SAP HANA is the halfway house. Migrating an ERP system to the HANA database declusters its cluster tables into transparent ones as standard, which is why SAP has a knowledge-base article for the cases where some weren't, and a FAQ specifically on converting cluster tables such as BSEG. One practical trap follows: a cluster table returned rows in key order as a side effect, and a declustered one does not. Code that relied on that order needs an explicit ORDER BY or a SORT.

What changed in S/4HANA

Two things happened at once. BSEG became a normal transparent table, and ACDOCA took over the ledger.

QuestionECCS/4HANA
Is BSEG a cluster table?Yes, in RFBLG (unless the database is HANA)No, a transparent table
What does BSEG hold?All FI line itemsThe entry view: one row per document line, not per ledger, plus open-item details such as payment terms
Where do balances come from?Totals tables (GLT0, FAGLFLEXT) and index tablesACDOCA; the old totals and index tables are compatibility views that read it
Are amounts signed?No, use SHKZGIn BSEG, still no; in ACDOCA, yes (HSL in company code currency, KSL in group currency, and further currency fields), with DRCRK as the indicator
Line limit per document999 (BUZEI)999 in BSEG still; ACDOCA-DOCLN has six digits, and BSEG lines can be summarized
Multiple ledgersSeparate new-G/L tablesOne ACDOCA row per line per ledger, distinguished by RLDNR

SAP's own documentation calls ACDOCA the single source of truth for accounting, and the compatibility views exist so that old code selecting from BSIS or FAGLFLEXT keeps running. Running is not the same as being the right source: a compatibility view is ACDOCA wearing an old name.

Three consequences matter for anyone reconciling the two. Line numbers don't map one-to-one: DOCLN is not BUZEI, ACDOCA can carry lines that BSEG summarized away, and every extra ledger adds rows. Some things never reach ACDOCA: SAP's knowledge base notes that noted items such as down-payment requests live in BSEG only. And on S/4HANA Cloud public edition you don't read tables at all: the released CDS views are the interface, with I_JournalEntry for the header, I_JournalEntryItem for universal-journal items and I_OperationalAcctgDocItem for the entry-view items that correspond to BSEG.

BSEG didn't disappear in S/4HANA; it stopped being the answer to "what's the balance?". Ask ACDOCA that question, and keep BSEG for "what exactly was posted on this document?"

When to read ACDOCA instead

Use ACDOCA (or I_JournalEntryItem) for balances, trial balances, P&L and balance-sheet slices, anything by profit centre, segment or cost object, and any question that is really "per ledger". Always restrict the ledger: without RLDNR, a company with a leading and a local ledger double-counts.

Signed balance per account from the universal journal โ€” illustrative S/4HANA
SELECT
  racct,                 -- G/L account
  SUM(hsl) AS net_local  -- already signed, company code currency
FROM acdoca
WHERE rclnt  = '100'
  AND rldnr  = '0L'      -- the ledger you report on
  AND rbukrs = '1000'
  AND gjahr  = '2026'
GROUP BY racct;

Keep the BKPF/BSEG join for document-level work: an audit trail or a drill-down from a document number, open-item and payment-term detail, clearing analysis, noted items, and tracing what a specific process posted. Tracing what an electronic bank statement run or a treasury TBB1 flow posting actually created is the everyday example.

Performance guidance

  • Always restrict company code and fiscal year, and the client if you are outside ABAP. On ACDOCA add the ledger. Most runaway queries on either table are missing one of these.
  • Select the columns you need. BSEG and ACDOCA are wide; SELECT * on ACDOCA pulls hundreds of columns from a column store.
  • ECC on a classic database: never search BSEG by a non-key field. Go through the index tables or through BKPF, then read BSEG by full key.
  • S/4HANA: aggregate in the database. A GROUP BY on ACDOCA is what the column store is built for; pulling line items into ABAP to sum them is the ECC habit to drop.
  • Don't join ACDOCA-DOCLN to BSEG-BUZEI and expect a one-to-one result. Reconcile at document level (company code, document number, year), then compare totals.
  • Sort explicitly. No former cluster table guarantees order any more.

Traps worth checking in any report

  • A join on BELNR alone, or on BELNR and BUKRS without GJAHR: correct in testing, wrong in the first year-end.
  • Summing unsigned DMBTR: a balance that is really turnover.
  • Summing ACDOCA without a ledger filter: every value doubled for each parallel ledger.
  • Reconciling ACDOCA line counts to BSEG line counts: summarization and ledgers make them differ by design.

For the treasury view of these tables, where TBB1 postings and the Treasury subledger meet the general ledger, see the SAP treasury tables reference; for what changes in a conversion, see migrating SAP treasury from ECC to S/4HANA.


See also SAP treasury tables, SAP TRM accounting and posting architecture and the SAP Treasury hub.

Share

Primary sources

SAP ERP 6.0 (ECC) on any database, including ECC on SAP HANA, and SAP S/4HANA on-premise and private edition. Table and field names are SAP data-dictionary names; the SQL and ABAP blocks are illustrative sketches for reading a replica or an S/4HANA system, not production code, and S/4HANA Cloud public edition exposes the released CDS views rather than the tables. Claims checked on 2026-09-25 through cross-checked excerpts of the listed sources.

Frequently asked questions

(4)

Which fields join BKPF to BSEG in SAP FI?

All four together: MANDT (client), BUKRS (company code), BELNR (document number) and GJAHR (fiscal year). BELNR is only unique within a company code and fiscal year, so a join on document number alone fans out across every company code and year that reuses it. BSEG's own key adds BUZEI, the line item number, which is why one BKPF row joins to many BSEG rows.

Why can't I just sum DMBTR to get an account balance?

DMBTR is stored as a positive number; the debit or credit direction is in SHKZG, where S is debit and H is credit. Summing DMBTR gives gross turnover, not a balance. Flip the sign for H rows, for example SUM(CASE WHEN shkzg = 'H' THEN -dmbtr ELSE dmbtr END). ACDOCA avoids the problem because its amount fields such as HSL are already signed.

Is BSEG still used in S/4HANA?

Yes. BSEG still exists in S/4HANA as a transparent table rather than a cluster table, and it still holds the entry view of each accounting document, one row per document line, along with open-item details such as payment terms. The ledger view lives in ACDOCA, the universal journal, which holds one row per line per ledger and is the source for balances and reporting. The old index and totals tables such as BSIS and FAGLFLEXT survive only as compatibility views.

Should I join BKPF and BSEG or read ACDOCA on S/4HANA?

Read ACDOCA, or its released CDS views, for balances, ledger-specific values and anything that needs controlling or profitability fields, filtering on the ledger. Keep the BKPF/BSEG join for document-level work: audit trails, drill-downs from a document number, open-item and payment-term detail, and noted items such as down-payment requests, which sit in BSEG but not in ACDOCA.