Skip to main content

SAP BW / BW/4HANA Connection

Extension Credit

This guide uses the erpl extension by the DuckDB community. Thanks to the contributors who made SAP BW/4HANA integration possible through RFC connections!

Connect flAPI to SAP BW (Business Warehouse) and BW/4HANA systems using the ERPL extension. Access InfoCubes, DSOs, and BEx queries for analytics APIs.

Prerequisites

  • SAP NetWeaver RFC SDK installed
  • SAP BW user with query authorizations
  • Network access to BW system

Quick Start

# flapi.yaml
connections:
sap-bw:
init: |
INSTALL erpl;
LOAD erpl;
properties:
ashost: bw.company.com # BW application server
sysnr: '00' # System number
client: '100' # Client
user: ${SAP_BW_USER} # BW user
passwd: ${SAP_BW_PASSWORD} # Password
lang: EN

Connection Parameters

Same as SAP ERP:

ParameterDescriptionRequiredExample
ashostSAP BW server hostnameYesbw.company.com
sysnrSystem numberYes'00'
clientClient numberYes'100'
userSAP usernameYes${SAP_BW_USER}
passwdSAP passwordYes${SAP_BW_PASSWORD}
langLanguageNoEN

Reading BW Data

InfoCube Queries

# sqls/sales-analysis.yaml
url-path: /sales/analysis/

request:
- field-name: year
field-in: query
required: true
validators:
- type: string
pattern: '^\d{4}$'
- field-name: region
field-in: query
required: false

template-source: sales-analysis.sql
connection:
- sap-bw
-- sqls/sales-analysis.sql
-- Query InfoCube for sales data
SELECT
/BIC/OCALYEAR as year,
/BIC/OCREGION as region,
/BIC/OCPRODUCT as product,
/BIC/OCUSTOMER as customer,
/BIC/OREVENUE as revenue,
/BIC/OQUANTITY as quantity,
/BIC/OMARGIN as margin
FROM {{conn.sap-bw.ashost}}./BIC/ASALES01 -- InfoCube technical name
WHERE /BIC/OCALYEAR = '{{params.year}}'
{{#params.region}}
AND /BIC/OCREGION = '{{params.region}}'
{{/params.region}}

DSO (DataStore Object) Queries

-- sqls/customer-360.sql
-- Query DSO for detailed customer data
SELECT
CUSTOMER_ID,
CUSTOMER_NAME,
SEGMENT,
TOTAL_PURCHASES,
LAST_ORDER_DATE,
LIFETIME_VALUE,
CHURN_RISK_SCORE
FROM {{conn.sap-bw.ashost}}./BIC/ACUST360 -- DSO technical name
WHERE ACTIVE_FLAG = 'X'
ORDER BY LIFETIME_VALUE DESC
LIMIT 1000

ADSO (Advanced DSO in BW/4HANA)

-- sqls/realtime-inventory.sql
-- Query ADSO for near real-time data
SELECT
PLANT,
MATERIAL,
STORAGE_LOCATION,
STOCK_QUANTITY,
LAST_UPDATE_TIMESTAMP
FROM {{conn.sap-bw.ashost}}./BIC/AINVENT01
WHERE LAST_UPDATE_TIMESTAMP >= CURRENT_TIMESTAMP - INTERVAL 1 HOUR

Common BW Objects

InfoCubes

Pre-aggregated analytical data:

  • 0SD_C03 - Sales analysis
  • 0PUR_C01 - Purchase analysis
  • 0FI_GL_4 - General ledger
  • /BIC/A* - Custom InfoCubes

DSOs

Detailed transactional data:

  • 0MATERIAL - Material master
  • 0CUSTOMER - Customer master
  • /BIC/A* - Custom DSOs

BEx Queries

Access published BEx queries via ERPL (requires RFC function modules).

Caching BW Data

Critical for BW: Queries can take 30+ seconds. Always cache:

# sqls/sales-dashboard.yaml
url-path: /sales/dashboard/

cache:
enabled: true
table: bw_sales_cache
schedule: 12h # BW updates overnight
template_file: sales_dashboard_cache.sql

template-source: sales_dashboard.sql
connection:
- sap-bw
-- sqls/sales_dashboard_cache.sql
-- Materialize complex BW query results
SELECT
c.CALYEAR as year,
c.CALMONTH as month,
r.REGION_TEXT as region,
p.PRODUCT_TEXT as product_category,
SUM(f.REVENUE) as total_revenue,
SUM(f.QUANTITY) as total_quantity,
AVG(f.MARGIN_PCT) as avg_margin_pct,
COUNT(DISTINCT f.CUSTOMER) as unique_customers
FROM {{conn.sap-bw.ashost}}./BIC/FSALES f -- Fact table
LEFT JOIN {{conn.sap-bw.ashost}}./BIC/PCALENDAR c
ON f.CALYEAR = c.CALYEAR AND f.CALMONTH = c.CALMONTH
LEFT JOIN {{conn.sap-bw.ashost}}./BIC/PREGION r
ON f.REGION = r.REGION
LEFT JOIN {{conn.sap-bw.ashost}}./BIC/PPRODUCT p
ON f.PRODUCT = p.PRODUCT
WHERE c.CALYEAR >= YEAR(CURRENT_DATE) - 2 -- Last 2 years
GROUP BY c.CALYEAR, c.CALMONTH, r.REGION_TEXT, p.PRODUCT_TEXT

Performance:

MethodQuery TimeAPI Response
Direct BW30-120 secondsTimeout
flAPI cacheN/A1-3ms

BW-Specific Considerations

1. Technical Names

BW uses cryptic technical names:

  • InfoCubes: /BIC/ASALES01, 0SD_C03
  • Characteristics: /BIC/OCUSTOMER, 0CALMONTH
  • Key figures: /BIC/OREVENUE, 0AMOUNT

Find names in:

  • Transaction RSA1 (Data Warehousing Workbench)
  • Transaction LISTCUBE (View InfoCube data)

2. Naming Conventions

/BIC/A*  - Custom InfoCubes/DSOs
/BIC/O* - InfoObject characteristics
/BIC/P* - Master data tables
0* - SAP standard objects

3. Date/Time Fields

BW uses specific formats:

  • CALMONTH: YYYYMM (e.g., 202401)
  • CALDAY: YYYYMMDD (e.g., 20240115)
  • Convert in SQL: TO_DATE(CALDAY, 'YYYYMMDD')

4. Master Data

Join with master data for descriptions:

-- Join dimension with master data
SELECT
f.CUSTOMER,
m.CUSTOMER_NAME,
m.CITY,
m.COUNTRY,
SUM(f.REVENUE) as revenue
FROM {{conn.sap-bw.ashost}}./BIC/FSALES f
LEFT JOIN {{conn.sap-bw.ashost}}./BIC/PCUSTOMER m
ON f.CUSTOMER = m.CUSTOMER
GROUP BY f.CUSTOMER, m.CUSTOMER_NAME, m.CITY, m.COUNTRY

Complete Example

# ═══════════════════════════════════════════════════════════════
# flapi.yaml - BW Connection
# ═══════════════════════════════════════════════════════════════
connections:
sap-bw-prod:
init: |
INSTALL erpl;
LOAD erpl;
properties:
ashost: ${SAP_BW_HOST}
sysnr: ${SAP_BW_SYSNR}
client: ${SAP_BW_CLIENT}
user: ${SAP_BW_USER}
passwd: ${SAP_BW_PASSWORD}
lang: EN

# ═══════════════════════════════════════════════════════════════
# sqls/revenue-report.yaml
# ═══════════════════════════════════════════════════════════════
url-path: /reports/revenue/

authentication:
required: true
methods: [jwt]
roles: [reporting-user]

cache:
enabled: true
table: bw_revenue_report
schedule: 24h # Daily refresh
on_startup: true # Load on flAPI start
template_file: revenue_cache.sql

request:
- field-name: year
field-in: query
description: Fiscal year (YYYY)
required: false
default: "2024"

- field-name: region
field-in: query
description: Region code
required: false
validators:
- type: string
enum: [EMEA, AMER, APAC]

template-source: revenue_report.sql
connection:
- sap-bw-prod
-- sqls/revenue_cache.sql
-- Daily materialization from BW InfoCube
SELECT
TO_DATE(fc.CALMONTH || '01', 'YYYYMMDD') as month_date,
SUBSTRING(fc.CALMONTH, 1, 4) as year,
SUBSTRING(fc.CALMONTH, 5, 2) as month,
reg.REGION_TEXT as region,
pc.PRODUCT_CAT_TEXT as product_category,
cc.COUNTRY_TEXT as country,
SUM(fc.NET_REVENUE) as net_revenue,
SUM(fc.GROSS_REVENUE) as gross_revenue,
SUM(fc.QUANTITY) as quantity_sold,
COUNT(DISTINCT fc.ORDER_NUMBER) as order_count,
AVG(fc.MARGIN_PCT) as avg_margin_pct
FROM {{conn.sap-bw-prod.ashost}}./BIC/AREVENUE01 fc -- Revenue InfoCube
LEFT JOIN {{conn.sap-bw-prod.ashost}}./BIC/PREGION reg
ON fc.REGION = reg.REGION
LEFT JOIN {{conn.sap-bw-prod.ashost}}./BIC/PPRODCAT pc
ON fc.PRODUCT_CAT = pc.PRODUCT_CAT
LEFT JOIN {{conn.sap-bw-prod.ashost}}./BIC/PCOUNTRY cc
ON fc.COUNTRY = cc.COUNTRY
WHERE SUBSTRING(fc.CALMONTH, 1, 4) >= '2020' -- Since 2020
AND fc.RECORD_MODE = 'A' -- Active records only
GROUP BY fc.CALMONTH, reg.REGION_TEXT, pc.PRODUCT_CAT_TEXT, cc.COUNTRY_TEXT
-- sqls/revenue_report.sql
-- Fast API queries against materialized cache
SELECT
year,
month,
month_date,
region,
product_category,
country,
net_revenue,
gross_revenue,
quantity_sold,
order_count,
avg_margin_pct
FROM bw_revenue_report
WHERE 1=1
{{#params.year}}
AND year = '{{params.year}}'
{{/params.year}}
{{#params.region}}
AND region = '{{params.region}}'
{{/params.region}}
ORDER BY month_date DESC, net_revenue DESC

Best Practices

✅ DO

  • Cache aggressively (BW queries are slow)
  • Refresh overnight when BW updates
  • Use master data joins for readable output
  • Filter by date ranges to limit data volume
  • Test queries in SE16N/LISTCUBE first
  • Request BW indexes on frequently filtered fields

❌ DON'T

  • Query BW directly without caching
  • Use SELECT * on large InfoCubes
  • Expose raw technical names in APIs
  • Query historical data without date filters
  • Run real-time queries against InfoCubes

Troubleshooting

No Data Returned

-- Check if data exists
SELECT COUNT(*) FROM {{conn.sap-bw.ashost}}./BIC/ASALES01

Common causes:

  • Wrong technical name
  • No data for filter criteria
  • Need to activate DSO/InfoCube
  • Authorization missing

Slow Queries

BW query taking > 60 seconds:

Solutions:

  1. ✅ Enable caching (required)
  2. ✅ Add date range filters
  3. ✅ Request BW team add indexes
  4. ✅ Use aggregated InfoCubes instead of DSOs
  5. ✅ Pre-aggregate in cache template

Authorization Issues

Error: RFC_ERROR_AUTHORITY

Required authorizations:

  • S_RFC - RFC authorization
  • S_RS_COMP - BW component authorization
  • Query-specific authorizations

Contact SAP Basis/BW team.

Environment Setup

# .env
export SAP_BW_HOST="bw-prod.company.com"
export SAP_BW_SYSNR="00"
export SAP_BW_CLIENT="100"
export SAP_BW_USER="BW_API_USER"
export SAP_BW_PASSWORD="secure-password"

Next Steps

🍪 Cookie Settings