diff --git a/docs/pages/product/data-modeling/concepts/multi-stage-calculations.mdx b/docs/pages/product/data-modeling/concepts/multi-stage-calculations.mdx index d2b227764d9ab..1ec39239c2b91 100644 --- a/docs/pages/product/data-modeling/concepts/multi-stage-calculations.mdx +++ b/docs/pages/product/data-modeling/concepts/multi-stage-calculations.mdx @@ -29,6 +29,7 @@ Common uses of multi-stage calculations: - [Time-shift](#time-shift) calculations, e.g., year-over-year sales growth. - [Period-to-date](#period-to-date) calculations, e.g., year-to-date (YTD) analysis. - [Fixed dimension](#fixed-dimension) calculations, e.g., comparing individual items to a broader dataset or calculating percent of total. +- [Conditional measure](#conditional-measure) calculations, e.g., based on a dimension value. - [Ranking](#ranking) calculations. ## Rolling window @@ -400,6 +401,132 @@ Query and result: +## Conditional measure + +Conditional measure calculations can be used to create measures that depend on the value +of a dimension. Such measures are defined using the [`case` parameter][ref-case-measures] +and used together with [`switch` dimensions][ref-switch-dimensions]. + +```yaml +- name: amount_in_currency + multi_stage: true + case: + switch: "{CUBE.currency}" + when: + - value: EUR + sql: "{CUBE.amount_eur}" + - value: GBP + sql: "{CUBE.amount_gbp}" + else: + sql: "{CUBE.amount_usd}" + type: number +``` + +### Example + +Data model: + + + +```yaml +cubes: + - name: orders + sql: | + SELECT 1 AS id, 100 AS amount_usd UNION ALL + SELECT 2 AS id, 200 AS amount_usd UNION ALL + SELECT 3 AS id, 300 AS amount_usd UNION ALL + SELECT 4 AS id, 400 AS amount_usd UNION ALL + SELECT 5 AS id, 500 AS amount_usd + + dimensions: + - name: currency + type: switch + values: + - USD + - EUR + - GBP + + measures: + - name: amount_usd + sql: amount_usd + type: sum + + - name: amount_eur + sql: "{amount_usd} * 0.9" + type: number + + - name: amount_gbp + sql: "{amount_usd} * 0.8" + type: number + + - name: amount_in_currency + multi_stage: true + case: + switch: "{currency}" + when: + - value: EUR + sql: "{amount_eur}" + - value: GBP + sql: "{amount_gbp}" + else: + sql: "{amount_usd}" + type: number +``` + +```javascript +cube(`orders`, { + sql: ` + SELECT 1 AS id, 100 AS amount_usd UNION ALL + SELECT 2 AS id, 200 AS amount_usd UNION ALL + SELECT 3 AS id, 300 AS amount_usd UNION ALL + SELECT 4 AS id, 400 AS amount_usd UNION ALL + SELECT 5 AS id, 500 AS amount_usd + `, + + dimensions: { + currency: { + type: `switch`, + values: [`USD`, `EUR`, `GBP`] + } + }, + + measures: { + amount_usd: { + sql: `amount_usd`, + type: `sum` + }, + + amount_eur: { + sql: `${amount_usd} * 0.9`, + type: `number` + }, + + amount_gbp: { + sql: `${amount_usd} * 0.8`, + type: `number` + }, + + amount_in_currency: { + multi_stage: true, + case: { + switch: `${currency}`, + when: [ + { value: `EUR`, sql: `${amount_eur}` }, + { value: `GBP`, sql: `${amount_gbp}` } + ], + else: { sql: `${amount_usd}` } + }, + type: `number` + } + } +}) +``` + + + +Query and result: + + ## Ranking @@ -471,3 +598,5 @@ Query and result: [link-cte]: https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression [ref-ref-time-shift]: /product/data-modeling/reference/measures#time_shift [ref-calendar-cubes]: /product/data-modeling/concepts/calendar-cubes +[ref-case-measures]: /product/data-modeling/reference/measures#case +[ref-switch-dimensions]: /product/data-modeling/reference/types-and-formats#switch \ No newline at end of file diff --git a/docs/pages/product/data-modeling/reference/measures.mdx b/docs/pages/product/data-modeling/reference/measures.mdx index 7de4a76b86a21..780c8090d4f9a 100644 --- a/docs/pages/product/data-modeling/reference/measures.mdx +++ b/docs/pages/product/data-modeling/reference/measures.mdx @@ -847,6 +847,122 @@ cube(`sales`, { Named time shifts also allow to reuse the same time shift configuration across multiple measures and cubes where they are defined. +### `case` + +The `case` parameter is used to define conditional measures, i.e., measures that are +calculated based on the value of a [`switch` dimension][ref-switch-dimensions]. + + + +`case` measures are powered by Tesseract, the [next-generation data modeling +engine][link-tesseract]. Tesseract is currently in preview. Use the +`CUBEJS_TESSERACT_SQL_PLANNER` environment variable to enable it. + + + +You do not need to include the [`sql` parameter](#sql) if the `case` parameter is used. +However, the [`multi_stage` parameter](#multi_stage) must be set to `true` for `case` +measures. + + + +```javascript +cube(`orders`, { + // ... + + dimensions: { + currency: { + type: `switch`, + values: [ + `USD`, + `EUR`, + `GBP` + ] + } + }, + + measures: { + amount_usd: { + sql: `amount_usd`, + type: `sum` + }, + + amount_eur: { + sql: `amount_eur`, + type: `sum` + }, + + amount_gbp: { + sql: `amount_gbp`, + type: `sum` + }, + + amount_in_currency: { + multi_stage: true, + case: { + switch: `${CUBE.currency}`, + when: [ + { + value: `EUR`, + sql: `${CUBE.amount_eur}` + }, + { + value: `GBP`, + sql: `${CUBE.amount_gbp}` + } + ], + else: { + sql: `${CUBE.amount_usd}` + } + }, + type: `number` + } + } +}) +``` + +```yaml +cubes: + - name: orders + # ... + + dimensions: + - name: currency + type: switch + values: + - USD + - EUR + - GBP + + measures: + - name: amount_usd + sql: amount_usd + type: sum + + - name: amount_eur + sql: amount_eur + type: sum + + - name: amount_gbp + sql: amount_gbp + type: sum + + - name: amount_in_currency + multi_stage: true + case: + switch: "{CUBE.currency}" + when: + - value: EUR + sql: "{CUBE.amount_eur}" + - value: GBP + sql: "{CUBE.amount_gbp}" + else: + sql: "{CUBE.amount_usd}" + type: number +``` + + + ### `format` `format` is an optional parameter. It is used to format the output of measures @@ -943,3 +1059,4 @@ cubes: [ref-multi-stage]: /product/data-modeling/concepts/multi-stage-calculations [ref-time-shift]: /product/data-modeling/concepts/multi-stage-calculations#time-shift [ref-calendar-cubes]: /product/data-modeling/concepts/calendar-cubes +[ref-switch-dimensions]: /product/data-modeling/reference/types-and-formats#switch \ No newline at end of file diff --git a/docs/pages/product/data-modeling/reference/types-and-formats.mdx b/docs/pages/product/data-modeling/reference/types-and-formats.mdx index d55347037ce1b..88499c3218c4a 100644 --- a/docs/pages/product/data-modeling/reference/types-and-formats.mdx +++ b/docs/pages/product/data-modeling/reference/types-and-formats.mdx @@ -255,7 +255,7 @@ Performs a table count, similar to SQL's `COUNT` function. However, unlike writing raw SQL, Cube will properly calculate counts even if your query's joins will produce row multiplication. -You do not need to include a `sql` parameter for this type. +You do not need to include the `sql` parameter for the measure of this type. `drill_members` parameter is commonly used with type `count`. It allows users to click on the measure in the UI and inspect individual records that make up a @@ -761,6 +761,64 @@ cubes: +### `switch` + +`switch` type is used to define a dimension that can only take one of the predefined +set of values. It is similar to an enum type in programming languages. They are +particularly useful for defining [`case` measures][ref-case-measures]. + + + +`switch` dimensions are powered by Tesseract, the [next-generation data modeling +engine][link-tesseract]. Tesseract is currently in preview. Use the +`CUBEJS_TESSERACT_SQL_PLANNER` environment variable to enable it. + + + +You do not need to include the `sql` parameter for the dimension of this type. + + + +```javascript +cube(`orders`, { + // ... + + dimensions: { + currency: { + type: `switch`, + values: [ + `USD`, + `EUR`, + `GBP` + ] + } + } +}) +``` + +```yaml +cubes: + - name: orders + # ... + + dimensions: + - name: currency + type: switch + values: + - USD + - EUR + - GBP +``` + + + + + +When `switch` dimensions are queried or introspected using the [`/v1/meta` REST API +endpoint][ref-meta-api], they are represented as dimensions of type `string`. + + + ### `geo` `geo` dimension is used to display data on the map. Unlike other dimension types @@ -1098,4 +1156,7 @@ cubes: [link-strftime]: https://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html [link-d3-time-format]: https://d3js.org/d3-time-format [ref-viz-tools]: /product/configuration/visualization-tools -[ref-apis-support]: /product/apis-integrations/core-data-apis#data-modeling \ No newline at end of file +[ref-apis-support]: /product/apis-integrations/core-data-apis#data-modeling +[link-tesseract]: https://cube.dev/blog/introducing-next-generation-data-modeling-engine +[ref-case-measures]: /product/data-modeling/reference/measures#case +[ref-meta-api]: /product/apis-integrations/rest-api/reference#base_pathv1meta \ No newline at end of file