Sales Performance Insights

This solution sample provides an example on how to accelerate insights into sales performance health using SAP ERP or SAP BDC sourced data.

With it you can:

  • Optimize revenue by product, region, and sales organization.
  • Track performance across distribution channels and divisions.
  • Use AI to uncover fulfillment bottlenecks or on-time delivery trends that impact revenue and costs.

Reference architecture

A high level reference architecture provides an overview of the source specific data products required to feed this use case.

Sales Performance Insights solution sample reference architecture for Cortex Framework

Figure 1 . Sales Performance Insights solution sample reference architecture for Cortex Framework.

Required data products

If building on top of SAP ERP sourced data the following Cortex Framework data products are required:

  • Customers
  • Sales Documents
  • Sales Organizations
  • Materials

In addition, customers can also seamlessly combine other SAP ERP base tables, for example KNVV and VBAP , to enhance insights as shown in the code snippets .

If building on top of SAP BDC sourced data the following BDC data products are required:

  • Customer
  • Sales Order
  • Sales Organization Structure
  • Company
  • Product

Code snippets

The following code snippet provides an example on how to build a BigQuery data model for sales performance insights on top of Cortex Framework sourced SAP ERP data products or integration of SAP BDC data products.

  WITH 
  
 date_dimension 
  
 as 
  
 ( 
  
 SELECT 
  
 dt 
  
 as 
  
 date 
 , 
  
 CAST 
 ( 
 FORMAT_DATE 
 ( 
 '%Y%m%d' 
 , 
  
 dt 
 ) 
  
 AS 
  
 INT64 
 ) 
  
 as 
  
 date_int 
 , 
  
 FORMAT_DATE 
 ( 
 '%Y%m%d' 
 , 
  
 dt 
 ) 
  
 as 
  
 date_str 
 , 
  
 FORMAT_DATE 
 ( 
 '%Y-%m-%d' 
 , 
  
 dt 
 ) 
  
 as 
  
 date_str2 
 , 
  
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_year 
 , 
  
 IF 
 ( 
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 2 
 ), 
  
 1 
 , 
  
 2 
 ) 
  
 as 
  
 cal_semester 
 , 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_quarter 
 , 
  
 EXTRACT 
 ( 
 MONTH 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_month 
 , 
  
 EXTRACT 
 ( 
 WEEK 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_week 
 , 
  
 CAST 
 ( 
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 AS 
  
 STRING 
 ) 
  
 as 
  
 cal_year_str 
 , 
  
 IF 
 ( 
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 2 
 ), 
  
 '01' 
 , 
  
 '02' 
 ) 
  
 as 
  
 cal_semester_str 
 , 
  
 IF 
 ( 
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 2 
 ), 
  
 'S1' 
 , 
  
 'S2' 
 ) 
  
 as 
  
 cal_semester_str2 
 , 
  
 '0' 
  
 || 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_quarter_str 
 , 
  
 'Q' 
  
 || 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 cal_quarter_str2 
 , 
  
 FORMAT_DATE 
 ( 
 '%B' 
 , 
  
 dt 
 ) 
  
 as 
  
 cal_month_long_str 
 , 
  
 FORMAT_DATE 
 ( 
 '%b' 
 , 
  
 dt 
 ) 
  
 as 
  
 cal_month_short_str 
 , 
  
 '0' 
  
 || 
  
 ( 
 EXTRACT 
 ( 
 WEEK 
  
 FROM 
  
 dt 
 )) 
  
 as 
  
 cal_week_str 
 , 
  
 FORMAT_DATE 
 ( 
 '%A' 
 , 
  
 dt 
 ) 
  
 as 
  
 day_name_long 
 , 
  
 FORMAT_DATE 
 ( 
 '%a' 
 , 
  
 dt 
 ) 
  
 as 
  
 day_name_short 
 , 
  
 EXTRACT 
 ( 
 DAYOFWEEK 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 day_of_week 
 , 
  
 EXTRACT 
 ( 
 DAY 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 day_of_month 
 , 
  
 DATE_DIFF 
 ( 
 dt 
 , 
  
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 QUARTER 
 ), 
  
 DAY 
 ) 
  
 + 
  
 1 
  
 as 
  
 day_of_quarter 
 , 
  
 IF 
 ( 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 2 
 ), 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 dt 
 ), 
  
 IF 
 ( 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 = 
  
 3 
 , 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 dt 
 ) 
  
 - 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 QUARTER 
 ) 
  
 - 
  
 1 
 )), 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 dt 
 ) 
  
 - 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 ( 
 DATE_TRUNC 
 ( 
 DATE_SUB 
 ( 
 dt 
 , 
  
 INTERVAL 
  
 3 
  
 MONTH 
 ), 
  
 QUARTER 
 ))) 
  
 ) 
  
 ) 
  
 as 
  
 day_of_semester 
 , 
  
 EXTRACT 
 ( 
 DAYOFYEAR 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 day_of_year 
 , 
  
 IF 
 ( 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 2 
 ), 
  
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 || 
  
 'S1' 
 , 
  
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 || 
  
 'S2' 
  
 ) 
  
 as 
  
 year_semester 
 , 
  
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 || 
  
 'Q' 
  
 || 
  
 EXTRACT 
 ( 
 QUARTER 
  
 FROM 
  
 dt 
 ) 
  
 as 
  
 year_quarter 
 , 
  
 CAST 
 ( 
 FORMAT_DATE 
 ( 
 '%Y%m' 
 , 
  
 dt 
 ) 
  
 AS 
  
 STRING 
 ) 
  
 as 
  
 year_month 
 , 
  
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ) 
  
 || 
  
 ' ' 
  
 || 
  
 FORMAT_DATE 
 ( 
 '%b' 
 , 
  
 dt 
 ) 
  
 as 
  
 year_month2 
 , 
  
 FORMAT_DATE 
 ( 
 '%Y%U' 
 , 
  
 dt 
 ) 
  
 as 
  
 year_week 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 YEAR 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_first_day_of_year 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 YEAR 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_last_day_of_year 
 , 
  
 ( 
 EXTRACT 
 ( 
 MONTH 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 1 
 , 
  
 7 
 ) 
  
 AND 
  
 EXTRACT 
 ( 
 DAY 
  
 FROM 
  
 dt 
 ) 
  
 = 
  
 1 
 ) 
  
 as 
  
 is_first_day_of_semester 
 , 
  
 (( 
 EXTRACT 
 ( 
 MONTH 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 6 
 ) 
  
 AND 
  
 EXTRACT 
 ( 
 DAY 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 30 
 )) 
  
 OR 
  
 ( 
 EXTRACT 
 ( 
 MONTH 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 12 
 ) 
  
 AND 
  
 EXTRACT 
 ( 
 DAY 
  
 FROM 
  
 dt 
 ) 
  
 IN 
  
 ( 
 31 
 ))) 
  
 as 
  
 is_last_day_of_semester 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 QUARTER 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_first_day_of_quarter 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 QUARTER 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_last_day_of_quarter 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 MONTH 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_first_day_of_month 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 MONTH 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_last_day_of_month 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 WEEK 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_first_day_of_week 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 WEEK 
 ) 
  
 = 
  
 dt 
 ) 
  
 as 
  
 is_last_day_of_week 
 , 
  
 (( 
 MOD 
 ( 
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ), 
  
 4 
 ) 
  
 = 
  
 0 
  
 AND 
  
 MOD 
 ( 
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ), 
  
 100 
 ) 
  
 != 
  
 0 
 ) 
  
 OR 
  
 MOD 
 ( 
 EXTRACT 
 ( 
 YEAR 
  
 FROM 
  
 dt 
 ), 
  
 400 
 ) 
  
 = 
  
 0 
 ) 
  
 as 
  
 is_leap_year 
 , 
  
 ( 
 FORMAT_DATE 
 ( 
 '%A' 
 , 
  
 dt 
 ) 
  
 NOT 
  
 IN 
  
 ( 
 'Saturday' 
 , 
  
 'Sunday' 
 )) 
  
 as 
  
 is_week_day 
 , 
  
 ( 
 FORMAT_DATE 
 ( 
 '%A' 
 , 
  
 dt 
 ) 
  
 IN 
  
 ( 
 'Saturday' 
 , 
  
 'Sunday' 
 )) 
  
 as 
  
 is_week_end 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 WEEK 
 )) 
  
 as 
  
 week_start_date 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 WEEK 
 )) 
  
 as 
  
 week_end_date 
 , 
  
 ( 
 DATE_TRUNC 
 ( 
 dt 
 , 
  
 MONTH 
 )) 
  
 as 
  
 month_start_date 
 , 
  
 ( 
 LAST_DAY 
 ( 
 dt 
 , 
  
 MONTH 
 )) 
  
 as 
  
 month_end_date 
 , 
  
 ( 
 EXTRACT 
 ( 
 WEEK 
  
 FROM 
  
 LAST_DAY 
 ( 
 dt 
 , 
  
 ISOYEAR 
 )) 
  
 = 
  
 53 
 ) 
  
 as 
  
 has_53_weeks 
 FROM 
  
 UNNEST 
 ( 
 GENERATE_DATE_ARRAY 
 ( 
  
 DATE_SUB 
 ( 
  
 DATE_TRUNC 
 ( 
 CURRENT_DATE 
 (), 
  
 YEAR 
 ), 
  
 INTERVAL 
  
 20 
  
 YEAR 
 ), 
  
 LAST_DAY 
 ( 
 DATE_ADD 
 ( 
 CURRENT_DATE 
 (), 
  
 INTERVAL 
  
 20 
  
 YEAR 
 )), 
  
 INTERVAL 
  
 1 
  
 DAY 
 ) 
 ) 
  
 as 
  
 dt 
 ), 
 delivered_qty 
  
 AS 
  
 ( 
  
 SELECT 
  
 client_mandt 
 , 
  
 internal_reference_document_number_vgbel 
  
 AS 
  
 sales_document_id 
 , 
  
 internal_reference_document_item_vgpos 
  
 AS 
  
 item_id 
 , 
  
 SUM 
 ( 
 actual_quantity_delivered_in_sales_units_lfimg 
 ) 
  
 AS 
  
 total_delivered_qty 
  
 FROM 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 delivery_document_items 
  
 GROUP 
  
 BY 
  
 client_mandt 
 , 
  
 internal_reference_document_number_vgbel 
 , 
  
 internal_reference_document_item_vgpos 
 ) 
 SELECT 
  
 header 
 . 
 document_number_vbeln 
  
 AS 
  
 sales_document_id 
 , 
  
 item 
 . 
 item_number_posnr 
  
 AS 
  
 item_id 
 , 
  
 header 
 . 
 sales_organization_vkorg 
  
 AS 
  
 sales_organization_id 
 , 
  
 salesorg 
 . 
 name_vtext 
  
 AS 
  
 sales_organization_name 
 , 
  
 header 
 . 
 division_spart 
  
 AS 
  
 division_id 
 , 
  
 division 
 . 
 name_vtext 
  
 AS 
  
 division_name 
 , 
  
 header 
 . 
 sold_to_party_kunnr 
  
 AS 
  
 customer_id 
 , 
  
 customer 
 . 
 name1_name1 
  
 AS 
  
 customer_name 
 , 
  
 item 
 . 
 material_number_matnr 
  
 AS 
  
 product_id 
 , 
  
 product 
 . 
 material_text_maktx 
  
 AS 
  
 product_name 
 , 
  
 item 
 . 
 net_value_of_the_sales_document_item_in_document_currency_netwr 
  
 AS 
  
 net_value 
 , 
  
 header 
 . 
 document_currency_waerk 
  
 AS 
  
 document_currency 
 , 
  
 header 
 . 
 requested_delivery_date_vdatu 
  
 AS 
  
 requested_delivery_date 
 , 
  
 header 
 . 
 delivery_block_lifsk 
  
 AS 
  
 delivery_block_reason 
 , 
  
  
 -- Using vbap.gbsta for overall status in S4 
  
 foundation_item 
 . 
 gbsta 
  
 AS 
  
 overall_status 
 , 
  
  
 -- Deriving delivery status based on delivered quantity 
  
 CASE 
  
  
 WHEN 
  
 delivered_qty 
 . 
 total_delivered_qty 
  
 IS 
  
 NULL 
  
 OR 
  
 delivered_qty 
 . 
 total_delivered_qty 
  
 = 
  
 0 
  
 THEN 
  
 'A' 
  
 WHEN 
  
 delivered_qty 
 . 
 total_delivered_qty 
 < 
 item 
 . 
 cumulative_order_quantity_kwmeng 
  
 THEN 
  
 'B' 
  
 ELSE 
  
 'C' 
  
 END 
  
 AS 
  
 delivery_status 
 , 
  
  
 salesarea 
 . 
 bzirk 
  
 AS 
  
 sales_region 
 , 
  
  
 -- Date Dimensions for Document Date 
  
 dimensional_document_date 
 . 
 cal_year 
  
 AS 
  
 year_of_sales_document 
 , 
  
 dimensional_document_date 
 . 
 cal_month 
  
 AS 
  
 month_of_sales_document 
 , 
  
 dimensional_document_date 
 . 
 cal_quarter 
  
 AS 
  
 quarter_of_sales_document 
 , 
  
  
 -- Date Dimensions for Requested Delivery Date 
  
 dimensional_delivery_date 
 . 
 cal_year 
  
 AS 
  
 year_of_requested_delivery 
 , 
  
 dimensional_delivery_date 
 . 
 cal_month 
  
 AS 
  
 month_of_requested_delivery 
 , 
  
 dimensional_delivery_date 
 . 
 cal_quarter 
  
 AS 
  
 quarter_of_requested_delivery 
 , 
  
  
 -- Calculated fields 
  
 CASE 
  
  
 WHEN 
  
 CURRENT_DATE 
 () 
 > 
 header 
 . 
 requested_delivery_date_vdatu 
  
  
 AND 
  
 ( 
 delivered_qty 
 . 
 total_delivered_qty 
  
 IS 
  
 NULL 
  
  
 OR 
  
 delivered_qty 
 . 
 total_delivered_qty 
 < 
 item 
 . 
 cumulative_order_quantity_kwmeng 
 ) 
  
  
 THEN 
  
 TRUE 
  
  
 ELSE 
  
 FALSE 
  
  
 END 
  
 AS 
  
 is_delivery_overdue 
 FROM 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 sales_document_headers 
  
 AS 
  
 header 
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 sales_document_items 
  
 AS 
  
 item 
  
 ON 
  
 header 
 . 
 client_mandt 
  
 = 
  
 item 
 . 
 client_mandt 
  
 AND 
  
 header 
 . 
 document_number_vbeln 
  
 = 
  
 item 
 . 
 document_number_vbeln 
 -- Joins with Master Data Products for Text 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 customers_md 
  
 AS 
  
 customer 
  
 ON 
  
 header 
 . 
 client_mandt 
  
 = 
  
 customer 
 . 
 client_mandt 
  
 AND 
  
 header 
 . 
 sold_to_party_kunnr 
  
 = 
  
 customer 
 . 
 customer_number_kunnr 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 materials_md 
  
 AS 
  
 product 
  
 ON 
  
 item 
 . 
 client_mandt 
  
 = 
  
 product 
 . 
 client_mandt 
  
 AND 
  
 item 
 . 
 material_number_matnr 
  
 = 
  
 product 
 . 
 material_number_matnr 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 sales_organizations_md 
  
 AS 
  
 salesorg 
  
 ON 
  
 header 
 . 
 client_mandt 
  
 = 
  
 salesorg 
 . 
 client_mandt 
  
 AND 
  
 header 
 . 
 sales_organization_vkorg 
  
 = 
  
 salesorg 
 . 
 sales_organization_vkorg 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_PRODUCTS_DATASET 
> . 
 divisions_md 
  
 AS 
  
 division 
  
 ON 
  
 header 
 . 
 client_mandt 
  
 = 
  
 division 
 . 
 client_mandt 
  
 AND 
  
 header 
 . 
 division_spart 
  
 = 
  
 division 
 . 
 division_spart 
 -- Join with KNVV for Sales Org Region 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_FOUNDATION_DATASET 
> . 
 knvv 
  
 AS 
  
 salesarea 
  
 ON 
  
 header 
 . 
 client_mandt 
  
 = 
  
 salesarea 
 . 
 mandt 
  
 AND 
  
 header 
 . 
 sold_to_party_kunnr 
  
 = 
  
 salesarea 
 . 
 kunnr 
  
 AND 
  
 header 
 . 
 sales_organization_vkorg 
  
 = 
  
 salesarea 
 . 
 vkorg 
  
 AND 
  
 header 
 . 
 distribution_channel_vtweg 
  
 = 
  
 salesarea 
 . 
 vtweg 
  
 AND 
  
 header 
 . 
 division_spart 
  
 = 
  
 salesarea 
 . 
 spart 
 -- Join with vbap directly to get gbsta (Overall Status) 
 LEFT 
  
 JOIN 
  
< YOUR_PROJECT_ID 
> . 
< YOUR_CORTEX_DATA_FOUNDATION_DATASET 
> . 
 vbap 
  
 AS 
  
 foundation_item 
  
 ON 
  
 item 
 . 
 client_mandt 
  
 = 
  
 foundation_item 
 . 
 mandt 
  
 AND 
  
 item 
 . 
 document_number_vbeln 
  
 = 
  
 foundation_item 
 . 
 vbeln 
  
 AND 
  
 item 
 . 
 item_number_posnr 
  
 = 
  
 foundation_item 
 . 
 posnr 
 -- Join with delivered_qty CTE 
 LEFT 
  
 JOIN 
  
 delivered_qty 
  
 AS 
  
 delivered_qty 
  
 ON 
  
 item 
 . 
 client_mandt 
  
 = 
  
 delivered_qty 
 . 
 client_mandt 
  
 AND 
  
 item 
 . 
 document_number_vbeln 
  
 = 
  
 delivered_qty 
 . 
 sales_document_id 
  
 AND 
  
 item 
 . 
 item_number_posnr 
  
 = 
  
 delivered_qty 
 . 
 item_id 
 -- Joins for Date Dimensions 
 LEFT 
  
 JOIN 
  
 date_dimension 
  
 AS 
  
 dimensional_document_date 
  
 ON 
  
 header 
 . 
 document_date_audat 
  
 = 
  
 dimensional_document_date 
 . 
 date 
 LEFT 
  
 JOIN 
  
 date_dimension 
  
 AS 
  
 dimensional_delivery_date 
  
 ON 
  
 header 
 . 
 requested_delivery_date_vdatu 
  
 = 
  
 dimensional_delivery_date 
 . 
 date 
 

Enable AI agents

After creating your Sales Performance Insights data model in BigQuery, you can build a custom data agent . This lets you query sales trends and performance metrics directly using natural language, bypassing the need for complex SQL.

Design a Mobile Site
View Site in Mobile | Classic
Share by: