generate-cds-analytical-query
Generate an analytical CDS query (transient projection view with PROVIDER CONTRACT ANALYTICAL_QUERY) on top of an existing analytical cube. Use when asked to "create an analytical query", "build a KPI query on a cube", "generate an ANALYTICAL_QUERY view", or "expose a cube for analytics/embedded analytics".
How do I install this agent skill?
npx skills add https://github.com/arc-mcp/arc-1 --skill generate-cds-analytical-queryIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill generates and deploys SAP CDS analytical queries by retrieving system metadata, composing DDL code, and using specialized SAP tools to write and activate the definitions.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
What does this agent skill do?
Generate CDS Analytical Query
Generate an analytical CDS query — a transient projection view with provider contract analytical_query — on top of an existing analytical cube (@Analytics.dataCategory: #CUBE).
This skill replicates SAP Joule's "CDS Analytical Query Generation" capability by combining ARC-1 (SAP system access) with mcp-sap-docs (documentation & best practices). The query view is what end users consume in analytical clients (SAP Analytics Cloud, Analysis for Office, embedded analytics) — it selects measures and dimensions from a cube and arranges them on rows/columns/free axes.
Prerequisites — read this first
- Requires SAP_BASIS 7.57+ (S/4HANA 2022+). The
provider contract analytical_queryform is unavailable on 7.56 and earlier. Note thatSAPManage(action="probe")rap.availableis necessary but not sufficient — RAP shipped in 7.54, so atruedoes not confirm the 7.57 floor. To gate reliably, check the release directly, e.g.SAPQuery(sql="SELECT release FROM cvers WHERE component = 'SAP_BASIS'")and require>= 757; otherwise be ready for the provider-contract syntax error to surface at activation (Step 5) and stop there. - You need an existing cube. This skill projects ON a cube. If no cube exists yet, run the
generate-analytics-star-schemaskill first to build the cube + dimensions, then come back here.
Smart Defaults (apply silently, do NOT ask)
| Setting | Default | Rationale |
|---|---|---|
| Object type | DDLS | Analytical queries are CDS data definitions |
| Package | $TMP | Fast prototyping; ask before a transportable package |
| Authorization | #NOT_ALLOWED | Mandatory on analytical queries — any other value fails activation |
| Axis layout | Dimensions → #ROWS, measures → #COLUMNS | Sensible default grid; user can rearrange |
| ATC | No | Only run if user asks about code quality |
Input
The user provides a cube name (e.g., ZI_Sales_Cube) or a business description ("revenue by region and month"). Only the cube is strictly required; if the user gives a description, find the cube via Step 1.
Optionally:
- Query name (default: derive from the cube, e.g.
ZC_SalesQuery; must be ≤ 28 characters — the analytical engine prepends2Cto the runtime name) - Package (default
$TMP) - Measures / dimensions to expose (default: all measures + key dimensions from the cube)
Step 1: Resolve and read the cube
1a. Find the cube (if the user gave a description, not a name)
SAPSearch(query="<keyword>*", searchType="object", objectType="DDLS")
Pick the candidate whose name/description matches an analytical cube. If multiple match, list them and ask.
1b. Read the cube source and confirm it IS a cube
SAPRead(type="DDLS", name="<cube>")
Verify the source contains @Analytics.dataCategory: #CUBE (or @Analytics: { dataCategory: #CUBE ... }). If it does NOT, stop: an analytical query can only project on a cube or a dimension. Suggest generate-analytics-star-schema to build a cube first.
1c. Get the structured element list
SAPRead(type="DDLS", name="<cube>", include="elements")
This returns every field with key markers and types. Use it to classify each element:
- Measures — numeric fields carrying
@Aggregation.default(e.g.#SUM) in the cube source - Dimensions — key fields and foreign-key-association fields
- Units/currencies — fields referenced by
@Semantics.amount.currencyCode/@Semantics.quantity.unitOfMeasure
Step 2: Look up current analytical-query syntax
Ground the generation in current docs — do NOT rely on memory for annotation names:
search("CDS analytical query provider contract analytical_query transient view")
search("AnalyticsDetails.query.axis ROWS COLUMNS FREE")
Cite the doc IDs you used in your final summary. Key facts the docs confirm (7.58):
- Header form:
define transient view entity <name> provider contract analytical_query as projection on <cube> @AccessControl.authorizationCheck: #NOT_ALLOWEDis mandatory (queries can't be read via ABAP SQL → no DCL allowed; the cube's access control applies)- The
transientkeyword is mandatory (no HANA SQL view is generated) - You cannot define new associations or use
KEYin a query view - A calculated measure (arithmetic / CASE-on-a-measure) needs
@Aggregation.default: #FORMULA
Step 3: Compose the analytical query
Pick the template that matches the request.
Template A — simple projection (1+ dimensions on rows, 1+ measures on columns)
@EndUserText.label: 'Sales Analytical Query'
@AccessControl.authorizationCheck: #NOT_ALLOWED
define transient view entity ZC_SalesQuery
provider contract analytical_query
as projection on ZI_Sales_Cube
{
@AnalyticsDetails.query.axis: #ROWS
RegionId,
@AnalyticsDetails.query.axis: #FREE
CalendarYear,
@AnalyticsDetails.query.axis: #COLUMNS
@Semantics.amount.currencyCode: 'CurrencyCode'
SalesAmount,
CurrencyCode
}
Template B — restricted + calculated measures
@EndUserText.label: 'Sales KPI Query'
@AccessControl.authorizationCheck: #NOT_ALLOWED
define transient view entity ZC_SalesKpiQuery
provider contract analytical_query
as projection on ZI_Sales_Cube
{
@AnalyticsDetails.query.axis: #ROWS
RegionId,
// restricted measure: selection-related CASE — WHEN must reference a DIMENSION
@Semantics.amount.currencyCode: 'CurrencyCode'
case when CalendarYear = '2025' then SalesAmount else null end as SalesAmount2025,
// calculated measure: formula CASE — needs @Aggregation.default: #FORMULA
@Aggregation.default: #FORMULA
case when SalesAmount is initial then abap.int8'0' else abap.int8'1' end as HasSales,
CurrencyCode
}
Template C — query with input parameters (filter prompt)
@EndUserText.label: 'Sales Query (parameterized)'
@AccessControl.authorizationCheck: #NOT_ALLOWED
define transient view entity ZC_SalesParamQuery
provider contract analytical_query
with parameters
p_year : abap.numc(4)
as projection on ZI_Sales_Cube
{
@AnalyticsDetails.query.axis: #ROWS
RegionId,
@Semantics.amount.currencyCode: 'CurrencyCode'
SalesAmount,
CurrencyCode
}
where CalendarYear = $parameters.p_year
Composition rules (enforce before writing):
- Every element you project directly from the cube must use the cube's exact element name (you read them in Step 1c). Calculated and restricted measures (Template B) are the exception — they introduce new aliases (
... as SalesAmount2025) that need not exist in the cube. - Every amount measure needs a
@Semantics.amount.currencyCode: '<field>'and that currency field must also be projected. - Every quantity measure needs
@Semantics.quantity.unitOfMeasure: '<field>'and that unit field must be projected. - Query name ≤ 28 chars.
Step 4: Show the plan, then write
Show the user the composed DDL and the axis layout (which fields are rows / columns / free) before writing. On confirmation:
SAPWrite(action="create", type="DDLS", name="<query>", source="<ddl>", package="$TMP")
For a transportable package, pass package="<pkg>" and transport="<TR>" (the user must supply the TR; create one with SAPTransport if needed).
Step 5: Activate
SAPActivate(name="<query>", type="DDLS")
If activation fails, surface the diagnostics verbatim and let the user re-prompt. Do NOT silently retry. Common failures:
@AccessControl.authorizationChecknot#NOT_ALLOWED→ fix the annotation- Element not found in cube → you used a name not in the cube (re-check Step 1c)
- Measure missing currency/unit reference → add the
@Semantics.*annotation + project the currency/unit field - Name > 28 chars → shorten the query name
Step 6: Verify
SAPRead(type="DDLS", name="<query>", include="elements")
Confirm the query is live and the projected elements appear. Report success with the runtime name (2C<query>).
Error Handling
| Error | Cause | Fix |
|---|---|---|
| Projection target is not a cube | Tried to project on a plain view | Build a cube first via generate-analytics-star-schema |
provider contract syntax error | SAP_BASIS < 7.57 | Stop — analytical_query unsupported on this release |
| Authorization check error on activate | Used a value other than #NOT_ALLOWED | Set @AccessControl.authorizationCheck: #NOT_ALLOWED |
| Element does not exist | Element name typo vs cube | Re-read the cube elements (Step 1c) |
| Name too long | Query name > 28 chars | Shorten it |
Notes
- This skill only creates the query layer. To build the underlying cube + dimensions + texts, use
generate-analytics-star-schemafirst — the two skills chain: star-schema produces the cube, this skill projects on it. - For a transactional (RAP) service rather than analytics, use
generate-rap-serviceinstead. - BTP ABAP and on-prem 7.58 both support this; on 7.57 verify the exact provider-contract form via
search()first.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/arc-mcp/arc-1/generate-cds-analytical-query">View generate-cds-analytical-query on skillZs</a>