개요 및 학습할 내용
ABAP Analytical Query는 SAP S/4HANA의 분석 모델(Analytical Cube + Query) 위에서 사용자가 직접 조회 조건을 입력할 수 있도록 Variable을 제공합니다. Variable은 단순한 파라미터를 넘어, Value Help 연결, 기본값 자동 파생, 단일/범위/다중 선택 모드 지원 등 다양한 UX를 제공합니다. 이 글에서는 Analytical Query CDS View(@Analytics.query: true)에서 Variable을 정의하고 Value Help CDS View와 연결하는 패턴을 단계별로 다룹니다.
- Analytical Query Variable의 종류와 동작 방식 이해
@Consumption.filter.selectionType의 #SINGLE / #RANGE / #MULTIPLE 차이@Consumption.derivation으로 기본값(예: 로그인 사용자, 회계연도) 자동 파생- Value Help CDS View 연결 패턴 (
@ObjectModel.foreignKey.association,@Consumption.valueHelpDefinition) - Mandatory / Optional Variable이 Fiori 화면과 OData 쿼리에 미치는 영향
사전 준비
아래 항목을 미리 익히고 시작하면 흐름을 따라가기가 수월합니다.
- ABAP CDS View(
DEFINE VIEW ENTITY) 기본 문법과 association 정의 - Analytical Model 3계층 구조: Cube View → Query View → Consumption
- Fiori Elements Analytical List Page(ALP) 또는 Multi-Dimensional Report의 필터 영역 동작
- SAP Gateway 또는 RAP Service Binding으로 OData V4 노출 경험
환경 및 버전 정보
아래 환경에서 동작을 검증하는 것을 권장합니다. 버전이 낮을수록 annotation 일부가 지원되지 않을 수 있어, 사용 전 SAP Note와 릴리스 노트를 확인하는 것이 일반적입니다.
- SAP S/4HANA 2022 FPS02 이상 또는 S/4HANA Cloud Public Edition 2308 이상
- ABAP Platform 2023 / ABAP Cloud (Steampunk) 환경에서도 동일한 annotation 사용 가능
- 개발 도구: ADT(ABAP Development Tools) for Eclipse 최신 패치
- 미리보기: ADT의 Data Preview, Fiori Elements Preview, 또는 Analytical Query Browser(
RSRT후속 도구) - 권장 명명 규칙: Cube는
ZC_, Query는ZQ_, Value Help는ZI_..._VH
주의: @Analytics.query: true가 붙은 view에서만 Variable의 모든 annotation이 정상 해석됩니다. 일반 CDS view에서 동일 annotation을 사용하면 무시되거나 활성화 단계에서 경고가 발생할 수 있습니다.
핵심 개념 — Variable, Selection Type, Value Help
Analytical Query Variable은 "리포트 실행 시 사용자가 입력하는 필터값"입니다. 일반 CDS의 parameter(WITH PARAMETERS)와는 다르게, Query View의 element에 @Consumption.filter annotation을 붙여 정의합니다. 즉 "별도 입력칸"이 아니라 "실제 컬럼에 대한 필터 동작 자체를 사용자 입력으로 만든다"는 개념입니다.
비유하자면 일반 CDS parameter는 음식 주문 시 미리 적어둔 메모지(쿼리 실행 전 반드시 값이 정해져야 함)이고, Analytical Variable은 식당 테이블 위의 양념통(있어도 되고 없어도 되며, 사용자가 그때그때 조정)에 가깝습니다.
- selectionType
#SINGLE: 단일값만 허용 (예: 단일 회계연도)#RANGE: BETWEEN/GT/LT 등 범위 연산자 허용 (예: 게시일 from~to)#MULTIPLE: 여러 값 동시 선택 (예: 회사코드 여러 개)
- mandatory:
true이면 사용자가 값을 입력해야만 실행되며, Fiori 필터 바에 별표(*)가 표시됩니다. - defaultValue / derivation: 초기값을 정적으로 지정하거나,
@Consumption.derivation으로 시스템 컨텍스트(현재 사용자, 오늘 날짜, 현재 회계연도 등)에서 파생합니다. - Value Help: 입력 칸 옆 돋보기 버튼에서 호출되는 검색 도움말.
@Consumption.valueHelpDefinition또는 association 기반@ObjectModel.foreignKey.association으로 연결합니다.
구조를 그림으로 풀면 다음과 같습니다.
[ Basic View ZI_Sales ]
|
v
[ Cube View ZC_SalesCube ] @Analytics.dataCategory: #CUBE
|
v
[ Query View ZQ_SalesQuery ] @Analytics.query: true
| +-- element CompanyCode -> Variable (MULTIPLE, mandatory)
| +-- element FiscalYear -> Variable (SINGLE, derivation)
| +-- element PostingDate -> Variable (RANGE, optional)
|
v
[ Service Binding / Fiori ALP ]
실전 코드 3단계
1단계 — 기본 Variable 정의
가장 단순한 형태입니다. Cube View 위에 Query View를 올리고, 두 개의 element에 Variable annotation을 부여합니다. CompanyCode는 다중 선택 필수, FiscalYear는 단일 선택 옵션입니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Query - Basic Variables'
@Analytics.query: true
@OData.publish: false
define view entity ZQ_SALES_QUERY_BASIC
as select from ZC_SALES_CUBE
{
@Consumption.filter:
{ selectionType: #MULTIPLE,
multipleSelections: true,
mandatory: true }
key CompanyCode,
@Consumption.filter:
{ selectionType: #SINGLE,
mandatory: false,
defaultValue: '2026' }
key FiscalYear,
@Consumption.filter:
{ selectionType: #RANGE,
mandatory: false }
PostingDate,
@DefaultAggregation: #SUM
NetAmount,
Currency
}
활성화 후 ADT의 Data Preview에서 실행하면, 필터 바에 세 개의 Variable 입력 칸이 나타나고 CompanyCode에는 mandatory 표시가 붙습니다.
2단계 — Value Help 연결 + 기본값 파생
실무에서는 "사용자가 코드값을 외우게 하지 말 것"이 원칙입니다. Value Help CDS View를 별도로 만들고 association으로 연결합니다. 동시에 @Consumption.derivation으로 로그인 사용자의 기본 회사코드와 현재 회계연도를 자동 채워줍니다.
@EndUserText.label: 'Company Code Value Help'
@ObjectModel.resultSet.sizeCategory: #XS
@Search.searchable: true
define view entity ZI_COMPANYCODE_VH
as select from I_CompanyCode
{
@ObjectModel.text.element: ['CompanyCodeName']
@Search.defaultSearchElement: true
key CompanyCode,
@Semantics.text: true
CompanyCodeName,
Country,
ChartOfAccounts
}
이제 Query View에서 Value Help과 derivation을 묶어줍니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Query - With Value Help'
@Analytics.query: true
define view entity ZQ_SALES_QUERY_VH
as select from ZC_SALES_CUBE
association [0..*] to ZI_COMPANYCODE_VH as _CCodeVH
on $projection.CompanyCode = _CCodeVH.CompanyCode
{
@Consumption.filter:
{ selectionType: #MULTIPLE,
multipleSelections: true,
mandatory: true }
@Consumption.valueHelpDefinition:
[{ entity: { name: 'ZI_COMPANYCODE_VH',
element: 'CompanyCode' } }]
@ObjectModel.foreignKey.association: '_CCodeVH'
key CompanyCode,
@Consumption.filter:
{ selectionType: #SINGLE,
mandatory: true }
@Consumption.derivation:
{ lookupEntity: 'ZI_USER_DEFAULTS',
binding: [{ targetElement: 'UserName',
type: #SYSTEM_FIELD,
value: #USER }],
resultElement: 'DefaultFiscalYear' }
key FiscalYear,
@Consumption.filter:
{ selectionType: #RANGE,
mandatory: false }
PostingDate,
@DefaultAggregation: #SUM
NetAmount,
Currency,
_CCodeVH
}
핵심 포인트는 다음과 같습니다.
- foreignKey.association: Fiori 필터 칸에 description(회사명)을 함께 표시할 때 사용합니다.
- valueHelpDefinition: F4 검색창에 표시될 컬럼/검색 가능 필드를 지정합니다.
@Search.defaultSearchElement로 fuzzy 검색을 활성화하는 것이 일반적입니다. - derivation: 사용자별 기본값 테이블(
ZI_USER_DEFAULTS)에서 현재 사용자(SY-UNAME)로 lookup하여DefaultFiscalYear를 가져옵니다.
3단계 — 프로덕션 패턴 (성능/권한/검증)
운영 환경에서는 Value Help가 매번 수십만 건을 조회하지 않도록 사이즈 카테고리, 권한 체크, 그리고 사용자 입력 검증을 함께 설계합니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Query - Production'
@Analytics.query: true
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
define view entity ZQ_SALES_QUERY_PROD
with parameters
@Consumption.hidden: true
P_DisplayCurrency : vdm_v_display_currency
as select from ZC_SALES_CUBE
association [0..*] to ZI_COMPANYCODE_VH as _CCodeVH
on $projection.CompanyCode = _CCodeVH.CompanyCode
association [0..*] to ZI_PROFITCENTER_VH as _PCVH
on $projection.ProfitCenter = _PCVH.ProfitCenter
{
@Consumption.filter:
{ selectionType: #MULTIPLE,
multipleSelections: true,
mandatory: true }
@Consumption.valueHelpDefinition:
[{ entity: { name: 'ZI_COMPANYCODE_VH', element: 'CompanyCode' },
additionalBinding: [{ localElement: 'ControllingArea',
element: 'ControllingArea',
usage: #FILTER_AND_RESULT }] }]
@ObjectModel.foreignKey.association: '_CCodeVH'
key CompanyCode,
@Consumption.filter:
{ selectionType: #SINGLE, mandatory: true }
@Consumption.derivation:
{ lookupEntity: 'ZI_USER_DEFAULTS',
binding: [{ targetElement: 'UserName',
type: #SYSTEM_FIELD, value: #USER }],
resultElement: 'DefaultFiscalYear' }
key FiscalYear,
@Consumption.filter:
{ selectionType: #RANGE, mandatory: true,
defaultLowValue: 'FIRST_DAY_OF_YEAR',
defaultHighValue: 'TODAY' }
PostingDate,
@Consumption.filter:
{ selectionType: #MULTIPLE, multipleSelections: true }
@Consumption.valueHelpDefinition:
[{ entity: { name: 'ZI_PROFITCENTER_VH', element: 'ProfitCenter' } }]
@ObjectModel.foreignKey.association: '_PCVH'
ProfitCenter,
@DefaultAggregation: #SUM
@Semantics.amount.currencyCode: 'Currency'
NetAmount,
@Semantics.currencyCode: true
Currency,
_CCodeVH,
_PCVH
}
운영 환경 체크리스트입니다.
- 권한:
@AccessControl.authorizationCheck: #CHECK와 DCL(Data Control Language)로 회사코드/조직 단위 분리를 적용합니다. - Value Help 성능: VH view에
@ObjectModel.resultSet.sizeCategory를 적절히(보통#XS/#S) 지정하고, 필요 시 검색 인덱스(@Search.fuzzinessThreshold)를 조정합니다. - Range 기본값: 회계 리포트는 "연초~오늘"이 자주 쓰이므로
defaultLowValue/defaultHighValue로 사전 설정하는 것이 사용성 향상에 좋습니다. - additionalBinding: Value Help 결과를 다른 필터(예: ControllingArea)와 동기화해 잘못된 조합을 사전 차단합니다.
- 유닛 테스트: ABAP Unit으로 query view 호출 시 mandatory 누락, derivation 결과 정합성을 검증합니다.
흔한 실수와 트러블슈팅
Variable과 Value Help 구성에서 자주 마주치는 이슈를 FAQ 형식으로 정리합니다.
- Q1. 필터 바에 Variable이 보이지 않습니다.
대부분@Analytics.query: true가 누락되었거나, Cube/Dimension view에 annotation을 잘못 붙인 경우입니다. Variable annotation은 Query View 레벨에서만 효력을 갖는다는 점을 확인하세요. 또한 Service Binding 후 메타데이터 캐시를 재생성하지 않으면 Fiori 측에서 옛 정의를 사용할 수 있습니다. - Q2. Value Help을 열면 결과가 비어 있습니다.
VH view의@AccessControl.authorizationCheck가#CHECK인데 사용자에게 권한이 없거나,additionalBinding의localElement명이 query view 컬럼과 다른 경우가 흔합니다. ADT의 Element Info로 association path를 다시 검증하세요. - Q3. derivation 기본값이 채워지지 않습니다.
lookupEntity로 지정한 view가@ObjectModel.usageType.dataClass: #MASTER등으로 적절히 분류되어야 derivation 엔진이 이를 찾을 수 있습니다. binding의targetElement가 lookup view의 key와 정확히 일치하는지, 그리고 system field 타입(#USER,#SYSTEM_DATE)이 적절한지 확인하세요. - Q4. Mandatory인데 사용자가 빈값으로 실행 가능해 보입니다.
OData V4 클라이언트에서$apply쿼리를 직접 호출하면 Fiori UI의 mandatory 검증을 우회할 수 있습니다. 서버 사이드 보호를 위해 query view에 default value를 함께 지정하거나, CDS behavior에서 사전 검증 로직을 추가하는 것이 일반적입니다. - Q5. RANGE Variable에 BETWEEN을 입력하면 성능이 급격히 떨어집니다.
Cube view 단계에서 사용된 컬럼이 HANA 컬럼스토어 인덱스 친화적인지, 그리고 Calculation View로 변환된 후 partition pruning이 작동하는지 plan viz로 확인합니다.
다음으로 살펴볼 주제
Variable과 Value Help이 익숙해졌다면 아래 주제로 확장해보길 권장합니다.
- Hierarchy Variable: ProfitCenter/CostCenter 계층 노드 선택용 Variable
- Currency Conversion Variable:
P_DisplayCurrency와@Semantics.amount.currencyCode결합 - Time Dependent Master Data: KeyDate Variable로 시점 기준 마스터 조회
- RAP Behavior + Analytical Query: Draft 데이터에 대한 분석 필터 패턴
- Custom Analytical Query in Embedded Analytics: KPI 타일, Story 연결
참고 자료
- SAP Help — CDS Analytical Query Annotations
- SAP Help — Embedded Analytics for S/4HANA
- SAP Help — ABAP CDS Annotations Reference
- SAP Community — ABAP CDS Views
- SAP Blogs — Analytical Query Variable 사례 모음
- SAP Help — Value Help in CDS (Consumption.valueHelpDefinition)
- SAP Developers — ABAP Platform Tutorials
핵심 한 줄
Analytical Query Variable은 @Consumption.filter로 선택 모드를, @Consumption.valueHelpDefinition으로 검색 UX를, @Consumption.derivation으로 기본값을 결정하는 세 축의 조합으로 설계하는 것이 핵심입니다.
댓글 0
아직 댓글이 없습니다.