Skip to Content

Purpose of this blog

The first purpose of the blog is to provide an overview of CDS View and explain the differences between the CDS View types. There are many types of CDS Views, and characteristics and the definition are quite different. Some are positioned as data layer and others are positioned as application objects and consumed by applications.

There are Master CDS Views, Transaction CDS Views, CDS Views published as OData Services, CDS Views with UI annotation and Analytic Query etc. In addition, CDS Views for data extraction and CDS API Views are available.

The second purpose of this blog is to provide example source code  for each of the CDS View types from the Predefined Virtual Data Model (VDM).

To understand the source code, I think the best way is to refer to the example source code, and it is also the case for ABAP CDS View. Other than Standard DEMO Examples of ABAP CDS views, you can see Predefined VDMs as examples to understand CDS Views. Unlike examples from DEMO CDS Views, you  see CDS Views based on the real business entities from Predefined VDMs. Simple examples for study may help, but sometimes the requirement in real world is more complex, so the samples  from a real case would be more helpful.

 

My motivation to write this blog

CDS View is one of the key of S/4HANA architecture principles. Pushdown (execute within the HANA DB Engine) is included automatically when CDS Views  are used, and CDS Views are the foundation of Fiori applications. However, CDS Views may not be so  easy to understand. One reason is many of the published  documents focus only on particular types of CDS View, e.g. Many  documents about Fiori Development, focus only on CDS View with UI annotation, and  Analytic Query, details about Interface Views are not included. I feel a holistic view is what is expected.  I also belive general SQL knowledge is not enough,   where knowledge applying to application specific settings are  also required,  including  SAP specific characteristics, e.g. association.

I’m writing  this blog to help  address the current situation, of missing a holistic view, with all required insights available in one place.

 

 Blog Contents

  • CDS View types overview

  • How to open CDS View in ADT (ABAP Development Tools)

  • Detail of CDS View types

    • Interface View

    • Consumption View

    • Other important Predefined CDS Views

  • How to find Predefined VDM used in a Fiori Application

Due to the inclusion of source code within the section “Detail of Predefined VDM Types”, this blog will appear somewhat lengthy. However this example code is only a copy from an S/4HANA system, for ease of reading, you may prefer to skip this code and refer the source code within your own S/4HANA system.

 

CDS View types overview

CDS View types:

 

  • Interface View: This view is the foundation for Consumption Views (Tech naming pattern: I_*). Master View and Transaction View are both of the type “interface”.
    • Transaction CDS View and Master CDS View are not official terms, but my own terms. I differentiate them as the purpose, structure and settings are different. I dear to differentiate Transaction CDS View and Master CDS View because I believe it helps understanding better. Profit Center is obviously master data, and it is clear that Purchase Order is transaction data from semantic point of view, and technically characteristics of master view and transaction view are quite different in practice. In some cases, whether it is Transaction or Master is unclear, e.g. Billing document is obviously transactional entity but I_BillingDocumentItem might not be called so, as it does not have measures. But it is only exceptional case, and what is transaction and what is master is obvious in most cases.
  • Consumption View: The view consumed by applications (Tech naming pattern: C_*). Various Consumptrion View types are available depending on the application consuming the view, these include, CDS View published as OData Service, CDS View with UI Annotation, Analytic Query and CDS API View.
    • They are not official categories  other than CDS API View, but I differentiate them as the application to use them and settings are different.
  • Other important Predefined VDM: This blog includes other important views worth highlighting. CDS View as ODP Datasource can be used as a source to send the data to BW or other external system. Most of them are Interface View. Table Function is also important to realize complex requirements.
  • Private View is a view used as a part for Interface View and Consumption View, not supposed to be reused. There are 2 types in Interface View, Basic View and Composite View. Basic View is the view for an entity in S/4HANA and Consumption View consists of Basic View. This blog does not focus on those views as Private View and difference between Basic View and Composite View is not so important.

 

CDS View types and examples in this blog

1. Interface View

1.1. Master CDS View:I_Currency/I_ProfitCenter

1.2. Transaction CDS View: I_BillingDocumentItemCube

 

2. Consumption View:

2.1. CDS View published as OData Service: C_APFlexibleAging

2.2. CDS View with UI Annotation: C_SuplrEvalRspEvaluateST

2.3. Analytic Query: C_Trialbalanceq0001

2.4. CDS API View: A_BankDetail

 

3. Other important Predefined VDMs

3.1. CDS View as ODP Datasource: I_BillingDocumentItem

3.2. CDS View including table function: P_SalesDocumentByMultObjSts

 

From the term “View”, you would imagine it is the combination of tables/views. However, in reality a Consumption View is rather a query or frontend object.

For those who may have some BW skills, we can compare some CDS Views to BW objects as follows:

Master CDS View is like an InfoObject (Charactersitic)

Transaction CDS View is like an InfoProvider (Transaction Basic View is like Infocube or ADSO

Transaction Composite View is like a Multiprovider or Composite Provider)

Consumption View is like a BW Query.

 

How to open CDS View in ADT

You can open the definition of the Predefined VDMs used in this blog with ADT as follows:

In ADT, Click “Open ABAP Development Object”.

Search with the DDL Source name (“I_PROFITCENTER” in the following case) and select the listed CDS View.

The definition of the CDS View is displayed.

 

Detail of CDS View types

1. Interface View

1.1 Master CDS View

  • In general, the source of a Master CDS View is an attribute table of the master data, text and hierarchy views, where the Master CDS View for each the attributes are associated.
  • In general, Analytic Data category is set as DIMENSION using the annotation “@Analytics.dataCategory”,   with the representative key  set using the annotation “@ObjectModel.representativeKey”.

A. Simple example: Currency code (I_Currency)

  • CDS View for Currency code (I_Currency) uses table TCURC and TCURX as a source which includes attribute data.
  • For Text data, I_CurrencyText is associated to the attribute and set as foreign key association using the annotation “@ObjectModel.text.association”.
  • Data Category is set as #DIMENSION.

 

I_Currency

@EndUserText.label: ‘Currency’

@ObjectModel.representativeKey: ‘Currency’

@ClientDependent: true

@Analytics: {dataCategory: #DIMENSION, dataExtraction.enabled: true}

@VDM.viewType: #BASIC

@AbapCatalog.sqlViewName: ‘IFICURRENCY’

@AccessControl.authorizationCheck: #NOT_REQUIRED

@Search.searchable: true

 

define view I_Currency

as select from tcurc

left outer join tcurx on tcurc.waers = tcurx.currkey

 

  association [0..*] to I_CurrencyText as _Text

    on $projection.Currency = _Text.Currency

{

 

@Semantics.currencyCode: true

@ObjectModel.text.association: ‘_Text’

key tcurc.waers as Currency,

_Text,

 

cast(COALESCE(tcurx.currdec, 2) as currdec) as Decimals,

 

@Search.defaultSearchElement: true

@Search.ranking: #HIGH

@Search.fuzzinessThreshold: 0.8

tcurc.isocd as CurrencyISOCode,

 

tcurc.altwr    as AlternativeCurrencyKey,

tcurc.xprimary as IsPrimaryCurrencyForISOCrcy

 

};

 

I_CurrencyText

  • Source is the text table of currency: TCURT
  • It has language key to which I_Language is associated.
  • Text field CurrencyName is set as text field using annotation “@Semantics.text”.
  • Object data category is set to #TEXT
@EndUserText.label: ‘Currency Text’
@ObjectModel.dataCategory: #TEXT
@ObjectModel.representativeKey: ‘Currency’
@Analytics.dataExtraction.enabled: true
@VDM.viewType: #BASIC
@AbapCatalog.sqlViewName: ‘IFICurrencyText’
@AccessControl.authorizationCheck: #NOT_REQUIREDdefine view I_CurrencyText
as select from tcurtassociation[1..1] to I_Currency as _Currency
on $projection.Currency = _Currency.Currency
association[0..1] to I_Language as _Language
on $projection.Language = _Language.Language
{
@Semantics.language: true
@ObjectModel.foreignKey.association: ‘_Language’
key spras as Language,
_Language,@Semantics.currencyCode: true
@ObjectModel.foreignKey.association: ‘_Currency’
key waers as Currency,
_Currency,@Semantics.text: true
ltext as CurrencyName,@Semantics.text: true
ktext as CurrencyShortName};   

 

Complex example: Profit Center (I_ProfitCenter)

I_ProfitCenter

  • CDS View for Profit Center (I_ProfitCenter) uses table CEPC as a source which includes attribute data
  • For Text data, I_ProfitCenterText is associated to the attribute and set as foreign key association.
  • For hierarchy data, I_ProfitCenterHierarchyNode is associated and set as hierarchy association using annotation “@ObjectModel.Hierarchy.association”.
  • For attributes, master view for them are associated to provide text and attributes of the attributes.

 

@EndUserText.label: ‘Profit Center’

@Analytics: { dataCategory: #DIMENSION, dataExtraction.enabled: true }

@VDM.viewType: #BASIC

@AbapCatalog.sqlViewName: ‘IFIPROFITCENTER’

@AccessControl.authorizationCheck: #CHECK

@AccessControl.privilegedAssociations:  [ ‘_ProfitCenterHierarchyNode’

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

,’_ControllingAreaText’,’_SegmentText’

// ]–GENERATED

]

@ObjectModel.representativeKey: ‘ProfitCenter’

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType: {

dataClass: #MASTER,

serviceQuality: #A,

sizeCategory: #M

}

@Search.searchable: true

define view I_ProfitCenter  as select distinct from cepc

 

 

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

association [1..1] to I_ControllingArea      as _ControllingAreaText on   $projection.ControllingArea = _ControllingAreaText.ControllingArea

association [0..*] to I_SegmentText      as _SegmentText on   $projection.Segment = _SegmentText.Segment

// ]–GENERATED

association[1..1] to I_ControllingArea           as _ControllingArea           on $projection.ControllingArea   = _ControllingArea.ControllingArea

association[0..*] to I_ProfitCenterText          as _Text                      on $projection.ControllingArea   = _Text.ControllingArea and

$projection.ProfitCenter      = _Text.ProfitCenter and

$projection.ValidityEndDate   = _Text.ValidityEndDate

association[0..*] to I_ProfitCenterHierarchyNode as _ProfitCenterHierarchyNode on $projection.ControllingArea   = _ProfitCenterHierarchyNode.ControllingArea and

$projection.ProfitCenter      = _ProfitCenterHierarchyNode.ProfitCenter

association[0..1] to I_Country                   as _Country                   on $projection.Country           = _Country.Country

association[0..1] to I_CompanyCode               as _Company                   on $projection.CompanyCode       = _Company.CompanyCode

association[0..1] to I_Segment                   as _Segment                   on $projection.Segment           = _Segment.Segment

association[0..1] to I_Region                    as _Region                    on $projection.Country           = _Region.Country and

$projection.Region            = _Region.Region

//association[0..*] to I_TaxJurisdiction           as _TaxJurisdiction           on $projection.TaxJurisdiction   = _TaxJurisdiction.TaxJurisdiction

association[0..1] to I_Language                  as _Language                  on $projection.Language = _Language.Language

association[1..1] to E_ProfitCenter               as _Extension               on  $projection.ControllingArea    = _Extension.ControllingArea

and  $projection.ProfitCenter      = _Extension.ProfitCenter

and  $projection.ValidityEndDate   = _Extension.ValidityEndDate

 

{

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.valueHelpDefinition: [

{ entity:  { name:    ‘I_ControllingArea’,

element: ‘ControllingArea’ }

}]

@ObjectModel.text.association: ‘_ControllingAreaText’

// ]–GENERATED

@ObjectModel.foreignKey.association: ‘_ControllingArea’

key kokrs  as ControllingArea,

@ObjectModel.text.association: ‘_Text’

@ObjectModel.Hierarchy.association: ‘_ProfitCenterHierarchyNode’

@Search.defaultSearchElement: true

@Search.fuzzinessThreshold: 0.8

key prctr  as ProfitCenter,

 

@Semantics.businessDate.to: true

key datbi  as      ValidityEndDate,

verak as          ProfitCtrResponsiblePersonName,

bukrs as          CompanyCode,

verak_user as     ProfitCtrResponsibleUser,

@Semantics.businessDate.from: true

datab as          ValidityStartDate,

abtei as          Department,

khinr as          ProfitCenterStandardHierarchy,

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.valueHelpDefinition: [

{ entity:  { name:    ‘I_SegmentStdVH’,

element: ‘Segment’ }

}]

@ObjectModel.text.association: ‘_SegmentText’

// ]–GENERATED

@ObjectModel.foreignKey.association: ‘_Segment’ //Inserted by VDM CDS Suite Plugin

segment as        Segment,

lock_ind as       ProfitCenterIsBlocked,

pca_template as   FormulaPlanningTemplate,

anred as          FormOfAddress,

name1 as          AddressName,

name2 as          AdditionalName,

name3 as          ProfitCenterAddrName3,

name4 as          ProfitCenterAddrName4,

stras as          StreetAddressName,

pfach as          POBox,

ort01 as          CityName,

pstlz as          PostalCode,

ort02 as          District,

@ObjectModel.foreignKey.association: ‘_Country’ //Inserted by VDM CDS Suite Plugin

land1 as          Country,

@ObjectModel.foreignKey.association: ‘_Region’

regio as          Region,

txjcd as          TaxJurisdiction,

@Semantics.language:true

@ObjectModel.foreignKey.association: ‘_Language’ //Inserted by VDM CDS Suite Plugin

spras as          Language,

telf1 as          PhoneNumber1,

telf2 as          PhoneNumber2,

telbx as          TeleboxNumber,

telx1 as          TelexNumber,

telfx as          FaxNumber,

datlt as          DataCommunicationPhoneNumber,

drnam as          ProfitCenterPrinterName,

usnam as          ProfitCenterCreatedByUser,

ersda as          ProfitCenterCreationDate,

 

_Text,

_Country,

_ControllingArea,

_ProfitCenterHierarchyNode,

_Language,

_Company,

_Segment,

_Region,

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.hidden: true

_ControllingAreaText,

@Consumption.hidden: true

_SegmentText

// ]–GENERATED

 

//_TaxJurisdiction

}

 

1.2. Transaction CDS View

Transaction CDS View is the foundation for the CDS View for applications. In the view, Master CDS Views are associated to attributes and the fields for measure are set as measure using annotation “@DefaultAggregation”. To be the foundation for the analytic query, it must be set as DIMENSION or CUBE in the annotation of Analytic Data category.

In Predefined VDM, in most Transaction Views, several Transaction View are created to create the one for the foundation of Consumption View. In the following case, I_BIllingDocumentItemCube is the source of Analytic Query C_SalesVolumeAnalysisQuery. I_BIllingDocumentItemCube is not created directly from VBRP but several Transaction CDS Views are created between the source transaction table and the Transaction View for Consumption View. But it is not mandatory to create several “nested” Transaction CDS Views.

 

Sample: I_BillingDocumentItemCube

  • Analytic Data Category is set to CUBE (or DIMENSION for some other Transaction CDS View) In this case, representative Key doesn’t have to be set. Then Analytic Query can be created on top of this view.
  • Master Data CDS Views are joined using association, and it is set as foreign key association with @ObjectModel.foreignKey.association, e.g. I_Product is associated and renamed to _Product, which is exposed (_Product is added in the selection field) and set to foreign key association to the field Product.
  • Fields for measure are set to be measure by using @DefaultAggregation and unit is associated.

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.dataClass: #MIXED

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.sizeCategory: #XL

@EndUserText.label: ‘Analytics – Sales Volume Cube’

@Analytics.dataCategory: #CUBE

@VDM.viewType: #COMPOSITE

@AccessControl.authorizationCheck:#CHECK

@AbapCatalog.sqlViewName: ‘ISDBILLGDOCITMC’

 

define view I_BillingDocumentItemCube

with parameters

P_ExchangeRateType : kurst,

P_DisplayCurrency  : vdm_v_display_currency

as select from I_BillingDocItemAnalytics as Item

left outer to one join I_SDDocStandardPartner     as HeaderPartner

on Item.BillingDocument = HeaderPartner.SDDocument

left outer to one join I_SDDocItemStandardPartner as ItemPartner

on  Item.BillingDocument = ItemPartner.SDDocument and Item.BillingDocumentItemInPartSgmt = ItemPartner.SDDocumentItem

left outer to one join I_CalendarDate as CalendarDate

on Item.CreationDate = CalendarDate.CalendarDate

left outer to one join I_CalendarDate as CalendarDateBillingDoc

on Item.BillingDocumentDate = CalendarDateBillingDoc.CalendarDate

left outer to one join I_EngagementProjectItem as CustomerProjectItem

on  Item.SalesDocument = CustomerProjectItem.EngagementProjectItem and CustomerProjectItem.EngagementProjectItemType = ‘0SOH’

association [0..1] to I_EngagementProject as _CustomerProject

on $projection.CustomerProject = _CustomerProject.EngagementProject

association [0..1] to I_Customer as _Customer

on $projection.Customer = _Customer.Customer

association [0..1] to I_Customer as _ShipToParty

on $projection.ShipToParty = _ShipToParty.Customer

association [0..1] to I_Customer as _BillToParty

on $projection.BillToParty = _BillToParty.Customer

association [0..1] to I_Employee as _SalesEmployee

on $projection.SalesEmployee = _SalesEmployee.PersonnelNumber

association [0..1] to I_Employee as _ResponsibleEmployee

on $projection.ResponsibleEmployee = _ResponsibleEmployee.PersonnelNumber

//Extension Association

association[0..1] to E_Billingdocumentitem as _Extension

on $projection.BillingDocument = _Extension.BillingDocument and $projection.BillingDocumentItem = _Extension.BillingDocumentItem

{

// Key

@ObjectModel.foreignKey.association: ‘_BillingDocument’

key BillingDocument,

key BillingDocumentItem,

 

// Key Association

_BillingDocument,

 

// Category

  @ObjectModel.foreignKey.association: ‘_SDDocumentCategory’

SDDocumentCategory,

  @ObjectModel.foreignKey.association: ‘_BillingDocumentCategory’

BillingDocumentCategory,

(omitted)

// Accounting

_CompanyCode,

_CustomerAccountAssgmtGroup,

_ExchangeRateType,

_DunningArea,

_DunningBlockingReason,

(omitted)

// Accounting

_CompanyCode,

_CustomerAccountAssgmtGroup,

(omitted)

// Analytics KPI

@Semantics.currencyCode: true

@ObjectModel.foreignKey.association: ‘_StatisticsCurrency’

  StatisticsCurrency,

_StatisticsCurrency,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘TransactionCurrency’

SalesVolumeNetAmount,

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

cast ( currency_conversion(

amount => SalesVolumeNetAmount,

source_currency => TransactionCurrency,

target_currency => :P_DisplayCurrency,

exchange_rate_date => BillingDocumentDate,

exchange_rate_type => :P_ExchangeRateType,

error_handling => ‘FAIL_ON_ERROR’,

round => #CDSBoolean.true,

decimal_shift => #CDSBoolean.true,

decimal_shift_back => #CDSBoolean.true

) as mc_umnetwr ) as SlsVolumeNetAmtInDspCrcy,

..

(omitted)…

 

2. Consumption View

2.1. CDS View published as OData Service

  • The CDS View published as OData Service can be used in Smart Business Apps including KPI tile, Analytical List Report (created with Fiori Report Design Modeler app) and Analysis Path Framework (APF).
  • The field to which exposed master view should be associated or to which text field is associated using @ObjectModel.text.element (e.g. C_BankRiskAnalytics) to group Key and text, which can be used in Smart Business apps. But it is not mandatory.
  • Other settings like “parameters” or “where conditions” can be included. In many of the SAP standard CDS Views for KPI Tiles, the parameter P_DateFunction is included with which the date or period can be filtered dynamically, e.g. C_OverduePO. See the blog for further details.
  • It is possible to create “calculated measures” with the AnalyticsDetail annotation (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘) for this view type. To do this , the view needs be set to Analytic Query (see below).
  • It is not mandatory to create from Interface view, but it is enough to be published as OData Service. It is technically no problem to include the settings normally in the Interface view, e.g. association, default aggregation, associating unit to measure in this view. Example of this type is C_PurOrdValueWithPlnd.

 

Example: C_APFlexibleAging (Used in Fiori App “Aging Analysis” (F1733))

@EndUserText.label: ‘Aging Analysis’

@VDM.viewType: #CONSUMPTION

@Analytics.query: true

@OData.publish: true

@AbapCatalog.sqlViewName: ‘CAPFLXBLAGING’

@AccessControl.authorizationCheck: #PRIVILEGED_ONLY

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.sizeCategory: #XXL

@ObjectModel.usageType.dataClass: #MIXED

@Metadata.ignorePropagatedAnnotations: true

define view C_APFlexibleAging

// Corresponds to calculation view ‘sap.hba.r.sfin700.AccountsPayableFlexibleAgingQuery’

with parameters

    @EndUserText.label: ‘Open on Key Date’

    @Consumption.defaultValue: ‘TODAY’

    @Consumption.valueHelpDefinition: [{

      entity: {

        name: ‘C_GregorianCalSglDateFuncVH’,

        element: ‘DateFunction’

      }

    }]

    P_DateFunction : datefunctionid,

   

    @Consumption.derivation: {

      lookupEntity: ‘I_SglGregorianCalDateFunction’,

      resultElement: ‘DateFunctionStartDate’,

      binding: [

        { targetParameter : ‘P_DateFunction’ ,

          type : #PARAMETER, value : ‘P_DateFunction’ }

      ]

    }

    @Consumption.hidden: true

    P_KeyDate : sydate,

   

    @Consumption.hidden: true

    @Environment.systemField: #SYSTEM_LANGUAGE

    P_Language : sylangu,

   

    @Consumption.defaultValue: ’15’

    P_AgingGridMeasureInDays : farp_aging_grid_measure,

 

    @Consumption.defaultValue: ‘4’

    P_NumberOfAgingGridColumns : farp_number_of_grid_columns,

   

    @Consumption.defaultValue: ‘EUR’   

    P_DisplayCurrency : vdm_v_display_currency

 

as select from

I_APFlexibleAging(

P_KeyDate : :P_KeyDate,

P_AgingGridMeasureInDays : :P_AgingGridMeasureInDays,

P_NumberOfAgingGridColumns : :P_NumberOfAgingGridColumns,

P_DisplayCurrency : :P_DisplayCurrency)

{

key CompanyCode,

key TransactionCurrency,

key GLAccount,

key Supplier,

//key PaymentTerms,

key AccountingDocumentCategory,

key AgingGridText,

 

_CompanyCode.CompanyCodeName as CompanyCodeName ,

_GLAccount._Text[1:Language = $parameters.P_Language].GLAccountLongName as GLAccountLongName,

_Supplier.SupplierName as SupplierName,

_AccountingDocumentCategory._Text[1:Language = $parameters.P_Language].AccountingDocumentCategoryName,

 

ChartOfAccounts,

_ChartOfAccounts._Text[1:Language = $parameters.P_Language].ChartOfAccountsName,

SupplierAccountGroup,

_SupplierAccountGroup._SupplierAccountGroupText[1:Language = $parameters.P_Language].AccountGroupName as SupplierAccountGroupName,

 

@Semantics.currencyCode:true

DisplayCurrency,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

AmountInDisplayCurrency_E,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

TotalNotOvrdAmtInDspCrcy,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

TotalOverdueAmtInDspCrcy_E

 

};

 

2.2. CDS View with UI Annotation

  • CDS View with UI Annotation can be used in Fiori Elements apps including List Report, Analytical List Page(ALP)/Object Page, Overview Page, Worklist/Object Page.
  • UI Annotations are included to define the UI setting of the Fiori Elements apps, e.g. OData Publish, @UI.lineItem is used for displaying the field in the initial screen, @UI.selectionField is used to set the field to be included in the selection field area in the initial screen.
    • It is not mandatory to include UI Annotation, but Settings for UI is possible using a Local Annotation with Annotation Modeler in Fiori Elements template in Web IDE. Please watch the movie for further details. This means, “CDS View published as OData Service” can also be the source of Fiori Elements apps.
  • It is possible to create “calculated measures” with AnalyticsDetail annotation (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘) for this view type. To enable this, the view needs to be set to Analytic Query (see below).
  • Search Annotation can be included to make freestyle search available.
  • Other settings like “parameters” or “where conditions” can be included. (But Parameter cannot be used in List Report by default)
  • It is not mandatory to create this view type from an Interface view, it is sufficient to be published as OData Service (the same as CDS View published as OData Service).

 

Example:C_CnsldtnJrnlEntr (Used in Fiori App “Display Group Journal Entries” (F2573)

@AbapCatalog.sqlViewName: ‘CCNSLDTNJRNLENTR’

@AbapCatalog.compiler.compareFilter: true

@AccessControl.authorizationCheck: #NOT_ALLOWED

@EndUserText.label: ‘Journal Entry Comsumption View’

@VDM.viewType: #CONSUMPTION

@ObjectModel.compositionRoot:true

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType: {

sizeCategory: #XXL,

serviceQuality: #D,

dataClass: #MIXED

}

 

@OData.publish: true

@UI.headerInfo: {

  typeName: ‘Journal Entry’,

  typeNamePlural: ‘Journal Entries’,

  title: {

    label: ‘Accounting Document Number’,

    value: ‘CnsldtnDocumentNumber’

  },

  description: {

    label: ‘Accounting Document Text’,

    value: ‘CnsldtnItemText’

  }

}

 

@UI.presentationVariant.requestAtLeast:  [ ‘CnsldtnRecordNumber’, ‘CnsldtnDimension’ ]

 

define view C_CnsldtnJrnlEntr

as select from I_CnsldtnJrnlEntr

association [0..*] to C_CnsldtnJrnlEntrItem as _Item on $projection.CnsldtnRecordNumber = _Item.CnsldtnRecordNumber

{

 

//@UI.lineItem: [{position:200,importance: #LOW}]

//@UI.hidden: true

key CnsldtnRecordNumber,

 

//Document Number

      @UI.lineItem.position: 10

CnsldtnDocumentNumber,

 

//Document Number line item

     @UI.lineItem: [{position:20,importance: #HIGH}]

CnsldtnPostingItem,

 

//Period e.g. 012 / 2016

@UI.lineItem: [{position:30,importance: #HIGH}]

      @UI.selectionField.position:20

      @UI.fieldGroup: [{qualifier:’FiscalPeriod’, groupLabel: ‘FiscalPeriod’, position: 10, importance: #HIGH}]

FiscalPeriod,

 

//Document Type

      @UI.lineItem: [{position:40,importance: #HIGH}]

      @UI.identification: {position: 10, importance: #HIGH}

CnsldtnDocumentType,

 

//Consolidation unit

      @UI.lineItem: [{position:50,importance: #HIGH}]

      @UI.selectionField.position:60

      @UI.identification: {position: 30, importance: #HIGH}

CnsldtnUnit,

 

//FS Item

     @UI.lineItem: [{position:60,importance: #HIGH}]

CnsldtnFinStmntItm,

 

//SubItem category

      @UI.lineItem: [{position:70,importance: #HIGH}]

      @UI.fieldGroup: [{qualifier:’UniqueSubAssignment’, groupLabel: ‘Unique Subassignments’, position: 10, importance: #HIGH}]

CnsldtnFinStmntSubItmCat,

 

(omitted)

//Amount in transaction currency

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘TransactionCurrency’

      @UI.lineItem: [{position:110,importance: #HIGH}]

AmountInTransactionCurrency,

 

//Amount in local currency

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘CnsldtnLocalCurrency’

      @UI.lineItem: [{position:120,importance: #HIGH}]

AmountInCnsldtnLocalCrcy,

 

(omitted)

 

2.3 Analytic Query

  • Analytic Query is a type of CDS View, which is exposed to the SAP HANA Analytical Engine so it can be used for multidimensional analytics, e.g. slicing, dicing and drilldown. It can be consumed just the same way as BW Queries, e.g. for testing with the BW transaction code RSRT, and for consumption via SAP Analysis for Office. It can be the source of Fiori Multidimensional Reporting app and SAP Analytics Cloud Online scenarios. It can also be used with BusinessObjects solution.
  • It is set as an Analytic Query with annotation @Analytics.query: true,
    • It needs to use the Interface View in which Analytic Data Category is set to #CUBE or #DIMENSION.
    • Association join cannot be set in an Analytic Query view.
    • Attributes of associated master view are ignored in Analytic Query views  (so the attributes of the associated master view  need to be set in the Interface view).
  • With AnalyticsDetails Annotations, default multidimensional layout of the query can be specified. The query must be set as Analytic Query (@Analytics.query: true). Restricted and Calculated Measure can be created.
    • When creating Calculated Measure with AnalyticsDetail Annotation, the Calculated Measure created in the same view can be used in the formula of another Calculated Measure. (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘ 1 as CM1, @AnalyticsDetails.query.formula: ‘ $projection.CM1/NETWR ’ 1 as CM12).
  • To define a specific behavior that relates to the consumption of CDS content through domain-specific frameworks, Consumption Annotations is used, e.g. to set an attribute as a prompt value, @Consumption.filter is used.
  • See Wiki page for more details relating to annotations in Analytic Query view.
  • Other settings like “parameters” or “where conditions”: can also be included.

 

Example: C_Trialbalanceq0001 (Used in Fiori App “Trial Balance” (F0996A))

@AbapCatalog.sqlViewName: ‘CFITRIALBALQ0001’

@EndUserText.label: ‘Trial Balance’

@VDM.viewType: #CONSUMPTION

@Analytics.query: true

@AccessControl.authorizationCheck: #PRIVILEGED_ONLY

@ClientHandling.algorithm: #SESSION_VARIABLE

@AbapCatalog.buffering.status: #NOT_ALLOWED

@Metadata.ignorePropagatedAnnotations: true

@ObjectModel.usageType.sizeCategory: #XXL

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.dataClass: #MIXED

 

define view C_Trialbalanceq0001

with parameters

@Consumption.hidden: true

@Environment.systemField: #SYSTEM_LANGUAGE

  P_Language        : sylangu,

@Consumption.hidden: true

@Environment.systemField: #SYSTEM_DATE

  P_KeyDate         : sydate,

 

@Consumption.derivation: { lookupEntity: ‘I_CalendarDate’,

    resultElement: ‘FirstDayofMonthDate’, binding: [

    { targetElement : ‘CalendarDate’ , type : #PARAMETER, value : ‘P_KeyDate’ } ]

   }   

  P_FromPostingDate : fis_budat_from,

 

@Consumption.derivation: { lookupEntity: ‘I_CalendarDate’,

    resultElement: ‘CalendarDate’, binding: [     

    { targetElement : ‘CalendarDate’ , type : #PARAMETER, value : ‘P_KeyDate’ } ]

   } 

  P_ToPostingDate   : fis_budat_to     

 

 

as select from I_GLAcctBalanceCube

( P_FromPostingDate: $parameters.P_FromPostingDate, P_ToPostingDate: $parameters.P_ToPostingDate )

 

{

 

// Filter/ Fixed Rows

@Consumption.filter: {selectionType: #SINGLE, multipleSelections: false, mandatory: true}

@Consumption.derivation: { lookupEntity: ‘I_LedgerStdVH’,

      resultElement: ‘Ledger’, binding: [

      { targetElement : ‘IsLeadingLedger’ , type : #CONSTANT, value : ‘X’ } ]

     }

@AnalyticsDetails.query.variableSequence : 10

//@AnalyticsDetails.query.axis: #FREE

Ledger,

 

@Consumption.filter: {selectionType: #RANGE, multipleSelections: true, mandatory: true}

@AnalyticsDetails.query.variableSequence : 20

@AnalyticsDetails.query.axis: #ROWS

@AnalyticsDetails.query.totals: #SHOW

CompanyCode,

_CompanyCode.CompanyCodeName,

 

(Omitted)

 

// Calculation of starting balance is done in the query for performance reasons

@AnalyticsDetails.query.axis: #COLUMNS

//@EndUserText.label: ‘Starting Balance CC’

@DefaultAggregation: #FORMULA

@Semantics.amount.currencyCode: ‘CompanyCodeCurrency’

@AnalyticsDetails.query.formula : ‘$projection.EndingBalanceAmtInCoCodeCrcy – $projection.DebitAmountInCoCodeCrcy – CreditAmountInCoCodeCrcy’

cast( cast( 1 as abap.dec(23,2)) as fis_start_bal_hsl_ui ) as StartingBalanceAmtInCoCodeCrcy,

 

 

// Debit and Credit Balance has an exception aggregation to make sure that LedgerFiscalYear is part of the select list

// this is necessary to push down the aggregation to the lowest level, since LedgerFiscalYear is part of the join condition of the FiscalCalenderDate

@AnalyticsDetails.query.axis: #COLUMNS

//@EndUserText.label: ‘Debit Balance CC’

@DefaultAggregation: #FORMULA

@Semantics.amount.currencyCode: ‘CompanyCodeCurrency’

@AnalyticsDetails: {

        exceptionAggregationSteps: [{ exceptionAggregationBehavior : #SUM,

                                      exceptionAggregationElements: [‘LedgerFiscalYear’]

                                   }]

    }

@AnalyticsDetails.query.formula : ‘$projection.GLAcctDebitAmtInCoCodeCrcy’ cast( cast( 1 as abap.dec(23,2)) as fis_dr_bal_hsl ) as DebitAmountInCoCodeCrcy, 

 

                                      exceptionAggregationElements: [‘FiscalPeriodDate’]

//                                      exceptionAggregationElements: [‘PostingDate’]

                                   }]

    }

@AnalyticsDetails.query.formula : ‘$projection.IntmdEndingBalAmtInCoCodeCrcy’ cast( cast( 1 as abap.dec(23,2)) as fis_end_bal_hsl_ui ) as EndingBalanceAmtInCoCodeCrcy, 

(Omitted)

 

2.4. CDS API View

  • CDS API View is supposed to be used as API.
  • It is not published as OData Service, and not set to Analytic Query.
  • Text field is not included.

 

Example: A_BankDetail

@AbapCatalog.sqlViewName: ‘ABKDET’

@EndUserText.label: ‘Remote API Contract for Bank Detail’

@VDM:{

viewType: #BASIC,

lifecycle.contract.type:#PUBLIC_REMOTE_API

}

 

@AccessControl.authorizationCheck: #CHECK

 

@ObjectModel: {

usageType: {

serviceQuality: #B,

sizeCategory:   #L,

dataClass:      #MASTER

}

}

@Metadata.ignorePropagatedAnnotations: true

@ClientHandling.algorithm: #SESSION_VARIABLE

@AbapCatalog.compiler.compareFilter: true

define view A_BankDetail as select from bnka {

 

key banks as BankCountry,

key bankl as BankInternalID,

banka as BankName,

swift as SWIFTCode,

bgrup as BankGroup,

bnklz as BankNumber,

provz as Region,

stras as StreetName,

ort01 as CityName,

brnch as Branch

 

//      xpgro as IsPostBankAccount,

//      loevm as IsMarkedForDeletion,

//      pskto as PostOfficeBankAccount,

//      chkme as CheckDigitCalculationMethod,

//      vers as BankDataFileFormat,

//      erdat as CreationDate ,

//      ernam as CreatedByUser,

//      adrnr as AddressID

}where loevm =or loevm = ‘ ‘;

 

 

3. Other important Predefined VDMs

3.1. CDS View as ODP Data Source

  • The CDS View can be used as a data source to send the data to BW system. It is a kind of ODP Data Source. The CDS View can be set to ODP Data Source with the annotation @Analytics.dataExtraction.enabled: true.
  • In the BW system connected to S/4HANA system (including embedded BW in S/4HANA), the CDS View can be replicated as ODP Data Source. See the blog in detail. This data source can also be used by DataServices, SDI etc. in the same way as a BW Data Source.
  • Most of the CDS  Views as ODP Data Source are Interface View. In those Interface View, the annotation @Analytics.dataExtraction.enabled: true is included.

 

Example: I_BillingDocumentItem

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.dataClass: #TRANSACTIONAL

@ObjectModel.usageType.serviceQuality: #A

@ObjectModel.usageType.sizeCategory: #XL

@ObjectModel.representativeKey: ‘BillingDocumentItem’

@EndUserText.label: ‘Billing Document Item’

@Analytics: { dataCategory: #DIMENSION, dataExtraction.enabled: true }

@VDM.viewType: #BASIC

@AccessControl.authorizationCheck:#CHECK

@AbapCatalog.sqlViewName: ‘ISDBILLGDOCITEM’

 

define view I_BillingDocumentItem

 

as select from P_BillingDocumentItemBasic

association[1..1] to I_BillingDocument   as _BillingDocument          on $projection.BillingDocument          = _BillingDocument.BillingDocument

//Extension Association

association[1] to E_Billingdocumentitem as _Extension on $projection.BillingDocument = _Extension.BillingDocument and $projection.BillingDocumentItem = _Extension.BillingDocumentItem

{

//Key

@ObjectModel.foreignKey.association: ‘_BillingDocument’

key BillingDocument,

key BillingDocumentItem,

 

//Category

// VBTYP as SDDocumentCategory,

SalesDocumentItemCategory,

SalesDocumentItemType,

ReturnItemProcessingType,

 

//Admin

CreatedByUser,

CreationDate,

CreationTime,

LogicalSystem,

..

(Omitted)..

..

 

3.2. CDS View including Table Function

(This example is to explain the technical characteristics, which is slightly different from the main topic of this blog. But  as it is so interesting and think it will help provide further context the Predefined VDM).

Table function can be the source of a CDS View, and Native SQL can be included in it. By using flexibility of Native SQL, a more sophisticated process might be possible. In Table Function, ABAP Managed Database Procedure (AMDP) is included in which Native SQL can be included.

 

Example: P_SalesDocumentByMultObjSts

@ClientHandling.type: #CLIENT_DEPENDENT

@ClientHandling.algorithm: #SESSION_VARIABLE

@AccessControl.authorizationCheck: #NOT_REQUIRED

@VDM.viewType: #BASIC

@VDM.private: true

 

define table function P_SalesDocumentByMultObjSts

with parameters

im_clnt : abap.clnt @<Environment.systemField: #CLIENT

returns

{

key Client                : mandt;

key SalesDocument         : vbeln_va;

key SalesDocumentItem     : posnr;

 

// System Status long name concatenated, max. 100 for one Item

SystemStatusName      : concat_sys_status_name;

 

// System Status short name concatenated, max. 100 for one Item

SystemStatusShortName : concat_sys_status_short_name;

 

// User Status long name concatenated, max. 100 for one Item

UserStatusName        : concat_user_status_name;

 

// User Status short name concatenated, max. 100 for one Item

UserStatusShortName   : concat_user_status_short_name;

 

}

implemented by method

CL_SD_SLSDOCBYOBJSTS=>CONCAT_STATUS_FOR_SLSDOC;

 

In the Native SQL of the AMDP, “string_agg” is used, which is not available in normal ABAP CDS Views.

CLASS CL_SD_SLSDOCBYOBJSTS DEFINITION

PUBLIC

FINAL

CREATE PUBLIC .

 

PUBLIC SECTION.

 

INTERFACES IF_AMDP_MARKER_HDB .

 

CLASS-METHODS CONCAT_STATUS_FOR_SLSDOC

FOR TABLE FUNCTION P_SALESDOCUMENTBYMULTOBJSTS .

 

PROTECTED SECTION.

PRIVATE SECTION.

ENDCLASS.

 

 

 

CLASS CL_SD_SLSDOCBYOBJSTS IMPLEMENTATION.

 

 

METHOD CONCAT_STATUS_FOR_SLSDOC BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY

USING PSLSDOCBYOBJSTS.

 

RETURN

SELECT “P1″.”MANDT”                                               AS Client,

“P1″.”SALESDOCUMENT”                                       AS SalesDocument,

“P1″.”SALESDOCUMENTITEM”                                   AS SalesDocumentItem,

 

string_agg ( concat(“P1″.”SYSTEMSTATUSNAME”, concat(‘ (‘, concat(“P1″.”SYSTEMSTATUSSHORTNAME”, ‘)\n’) ) ) )     AS SystemStatusName,

string_agg ( concat(“P1″.”SYSTEMSTATUSSHORTNAME”, ‘\n’) )  AS SystemStatusShortName,

 

string_agg ( concat(“P1″.”USERSTATUSNAME”, concat(‘ (‘, concat(“P1″.”USERSTATUSSHORTNAME”, ‘)\n’) ) ) )         AS UserStatusName,

string_agg ( concat(“P1″.”USERSTATUSSHORTNAME”, ‘\n’) )    AS UserStatusShortName

 

FROM “PSLSDOCBYOBJSTS” “P1”

GROUP BY “P1″.”MANDT”, “P1″.”SALESDOCUMENT”, “P1″.”SALESDOCUMENTITEM” ;

 

ENDMETHOD.

ENDCLASS.

 

Table function can be used in other CDS View.

P_SalesDocumentByMultObjSts is used in C_SalesDocumentByObjectStatus.

(omitted)

define view C_SalesDocumentByObjectStatus
as select from P_SalesDocumentByMultObjSts( im_clnt : $session.client )

association [0..1] to I_SalesDocument as _SalesDocument on $projection.SalesDocument = _SalesDocument.SalesDocument

(omitted)

 

 

Personal opinions:

  • “CDS View published as OData Service” or “CDS View with UI annotation” does not need to be created from Interface View technically, but I think it is better to do so as much as possible because of the standardization of the modeling. Anyway, application specific view needs to be created, and Interface View cannot be consumed by application directly in general.
    • This means, master view associations and foreign key associations should be set in Interface View as much as possible.
  • I think Interface View should be created to be supposed to be used for many purposes and should avoid having application specific settings as much as possible like BW Infoprovider and InfoObject are supposed to be reused for many reports.
    • So, In my opinion, Calculated measure (and Restricted measure) should be created in Consumption View, not in Interface View, as much as possible. It is because by using annotation “@AnalyticsDetails.query.formula”, the calculated measure created in the same analytic query can be used in the formula. In the standard predefined VDM used in KPI tile or Fiori Elements apps, it is not the case. But I think it is beneficial as we can avoid creating several source CDS Views to add calculated measures. But calculated measures/restricted measures supposed to be reused by many apps, it should be created in Interface View.
    • In addition, I believe parameters should be set in Consumption View, not in Interface View, as much as possible as in general parameters are application specific. But if the parameter values are not pushed down to the source tables/views, they need to be created in the lower views to use it in the WHERE condition explicitly. But as SELECT statement is optimized internally in HANA, WHERE conditions for normal columns (dynamically generated by the navigations in an application) should be pushed down to lower tables/views in general, so it is not necessary to use parameter instead of normal column filtering.
    • WHERE condition should not be included in Interface View as much as possible as Interface View should be supposed to be used also for the queries which need to all data in the source.

But they are only my current personal opinions, and I think there are some other ones who have different opinions but are also good. I would like you to share your opinions.

 

How to find Predefined VDM used in a Fiori app?

To find the CDS View used in Fiori apps, you can use List View of Fiori apps Library.

To get it, go to Fiori apps library for SAP S/4HANA > All Apps, and select “List View” on center bottom of the page.

 

In the  right, from “Column display settings” icon, select all columns to be displayed.

 

 

 

 

You can detect application types with the column “UITechnology”, e.g. “SAP Fiori: SAP Smart Business generic drill down app” which refers to  KPI tiles.

PrimaryODataServiceName column is the main OData Service used in the Fiori app. (“AdditionalODataServices” is other used OData Services). The name of the OData Services generated from CDS View ends with “_CDS”. (In the following sheet, new column I is created in which the formula is “=RIGHT(H,4)” for filtering with “_CDS”.

However the applications of UItechnology Fiori Design Studio (=Multidimensional Reporting) do not have an OData Service.

For these, you can run Transaction RSRT from a SAPGUI session within your S/4HANA system. In the InfoArea tree of the value help, the queries whose technical name start with “2CC” (the query name is “2C”+<SQL View name of the CDS View>. “2C” is prefix of Analytic Query, and SQL View name of Consumption View starts with “C”), can be selected. They are Analytic Queries of a Predefined VDM.

Push the Value Help button in the transaction RSRT.

Select an Analytic Query.

 

The view can be executed in this transaction.

 

  • Mapping between SQL View name and CDS View name can be checked in the table CDSSQLVIEW.

 

Training

It is recommended to participate in the following training courses.

S4D430 Building Views in Core Data Services ABAP (CDS ABAP)

S4H41E S/4HANA embedded analytics and Modeling Basics with Core Data Services (CDS Views)

or

S4H410 S/4HANA embedded analytics and Modeling Basics with Core Data Services (CDS Views)

 

Hope it help understanding overall of the CDS View!

To report this post you need to login first.

12 Comments

You must be Logged on to comment or reply to a post.

  1. Michelle Crapo

    I’m glad this is long as the examples help.  I’m using CDS views.  However, I believe there are times to use them and a time to just code for your tables.  What are your suggestions?   When would you create a CDS view?  Assuming one can’t be found that will work for you.  (or extended)

    (0) 
      1. Michelle Crapo

        I’m wondering when would you create a CDS view instead of just doing it in ABAP?  Sometimes, it is an easy choice if the CDS view is already available.

        (0) 
        1. Masaaki Arai
          Post author

          Hello Michelle,

          If Predefined VDM meets your customer’s requirement go with them. it it could meet by adding some fields, they can do that.

          But it is always the case that customer want to use their own CDS View to meet their own requirement, then Custom CDS View needs to be created. in my experience, most customers want to create their own CDS Views.

          For creating them, Key User Tools could be used, but the functionality is limited. Then the remaining way is to use ADT.

          In addition, even if standard Fiori app is used, IT team want to know the technologies used in the app. Then it is essential to understand the difference of the CDS View type.

          Thanks, Masa

           

          (0) 
    1. Masaaki Arai
      Post author

      Hello Syambabu,

      Below is the answer from DEV team.

      They are solely used to define OData services for external (cross system) consumption on them, and are kept stable across releases.

      They must not be used otherwise.

      Thanks, Masa

      (1) 
  2. Jack Chow

    Hi Masa,

    This is glad information, wanna to know the query part in RSRT. How to we create the selection parameter prompt like Variable? with default select last 3 month data? Still need to using CMOD coding?

    Thanks,

    Jack

     

     

    (0) 
    1. Masaaki Arai
      Post author

      Hello Jack,

      For analytical query, Consumption filter annotation “@Consumption.filter: {selectionType: #SINGLE, multipleSelections: false, mandatory: true}”, or Parameter should be used. See 2.3. Analytic Query in detail.

      btw, for Fiori Element app, ui annotation selection field needs to be used.

      Regarding the filtering time attributte, I would be happy if my blog could help.

      https://blogs.sap.com/2018/09/27/date-function-for-dynamic-date-filtering-in-fiori-apps/

      Thanks, Masa

      (0) 
  3. Jyoti Bhagat

    Hi Masa,

    Nice Blog!! Thanks for sharing the information.

    I would like to know where can I get information about CDS annotations apart from its documentation. I always get confused when to use which annotation and why. I have gone through all the SAP Help Documentation but that is not enough. Is there any source where I can get examples of the annotations?

    Thanks.

    (0) 

Leave a Reply