Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions docs/pages/product/data-modeling/concepts/multi-stage-calculations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -400,6 +401,132 @@ Query and result:

<Screenshot src="https://ucarecdn.com/0d0b318c-0743-4698-bb05-b9bf6dfeb292/" />

## 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:

<CodeTabs>

```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`
}
}
})
```

</CodeTabs>

Query and result:

<Screenshot src="https://lgo0ecceic.ucarecd.net/43df5a7c-7537-448a-999c-abeed5347519/" />

## Ranking

Expand Down Expand Up @@ -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
117 changes: 117 additions & 0 deletions docs/pages/product/data-modeling/reference/measures.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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].

<WarningBox>

`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.

</WarningBox>

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.

<CodeTabs>

```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
```

</CodeTabs>

### `format`

`format` is an optional parameter. It is used to format the output of measures
Expand Down Expand Up @@ -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
65 changes: 63 additions & 2 deletions docs/pages/product/data-modeling/reference/types-and-formats.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -761,6 +761,64 @@ cubes:

</CodeTabs>

### `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].

<WarningBox>

`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.

</WarningBox>

You do not need to include the `sql` parameter for the dimension of this type.

<CodeTabs>

```javascript
cube(`orders`, {
// ...

dimensions: {
currency: {
type: `switch`,
values: [
`USD`,
`EUR`,
`GBP`
]
}
}
})
```

```yaml
cubes:
- name: orders
# ...

dimensions:
- name: currency
type: switch
values:
- USD
- EUR
- GBP
```

</CodeTabs>

<InfoBox>

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`.

</InfoBox>

### `geo`

`geo` dimension is used to display data on the map. Unlike other dimension types
Expand Down Expand Up @@ -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
[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