Skip to content

Calculated Fields

Download this document

Calculated fields allow dynamically defining new columns in queries using expressions, without modifying TM/QM models.

1. Overview

There are two ways to define calculated fields:

  1. calculatedFields parameter: Defined in DSL requests
  2. Inline expressions: Directly write expression as alias in columns

2. Define via calculatedFields

2.1 Basic Format

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "netAmount",
                "caption": "Net Sales Amount",
                "expression": "salesAmount - discountAmount"
            }
        ],
        "columns": ["orderId", "salesAmount", "discountAmount", "netAmount"]
    }
}

2.2 Field Description

FieldTypeRequiredDescription
namestringYesField name, referenced in columns/slice/orderBy
captionstringNoDisplay name
expressionstringYesCalculation expression
descriptionstringNoField description
aggstringNoAggregation type (for autoGroupBy scenarios)

2.3 Column References in Expressions

Expressions can reference:

  • Property names in the model
  • Measure names in the model
  • Dimension columns: dimension$caption, dimension$id, dimension$property
  • Other calculated field names (must be defined before current field)

3. Define via Inline Expressions

Use expression as alias format directly in columns:

json
{
    "param": {
        "columns": [
            "orderId",
            "salesAmount",
            "salesAmount * 1.1 as adjustedAmount",
            "ROUND(salesAmount, 2) as roundedAmount"
        ]
    }
}

3.1 Aggregation Expressions

json
{
    "param": {
        "columns": [
            "product$categoryName",
            "sum(salesAmount) as totalSales",
            "count(*) as orderCount"
        ],
        "groupBy": [
            { "field": "product$categoryName" }
        ]
    }
}

Note: Inline expression aliases cannot conflict with existing field names in the model, otherwise an error will be thrown.


4. Supported Expressions

4.1 Arithmetic Operations

OperatorDescriptionExample
+AdditionsalesAmount + taxAmount
-SubtractionsalesAmount - discountAmount
*MultiplicationunitPrice * quantity
/DivisionprofitAmount / salesAmount
%Moduloquantity % 10

Compound Expressions:

(salesAmount - discountAmount) * 1.13

4.2 Math Functions

FunctionDescriptionExample
ABS(x)Absolute valueABS(discountAmount)
ROUND(x, n)RoundingROUND(salesAmount, 2)
CEIL(x)CeilingCEIL(quantity / 10)
FLOOR(x)FloorFLOOR(quantity / 10)
MOD(x, y)ModuloMOD(quantity, 10)
POWER(x, y)PowerPOWER(2, 3)
SQRT(x)Square rootSQRT(variance)

4.3 Date Functions

FunctionDescriptionExample
YEAR(date)Extract yearYEAR(salesDate$caption)
MONTH(date)Extract monthMONTH(salesDate$caption)
DAY(date)Extract dayDAY(salesDate$caption)
DATE(datetime)Extract date partDATE(orderTime)
NOW()Current timeNOW()
DATE_ADD(date, interval)Date additionDATE_ADD(orderDate, 7)
DATE_SUB(date, interval)Date subtractionDATE_SUB(orderDate, 7)
DATEDIFF(d1, d2)Date differenceDATEDIFF(NOW(), orderDate)

4.4 String Functions

FunctionDescriptionExample
CONCAT(a, b, ...)String concatenationCONCAT(orderId, '-', orderLineNo)
SUBSTRING(s, start, len)SubstringSUBSTRING(orderId, 1, 4)
UPPER(s)UppercaseUPPER(status)
LOWER(s)LowercaseLOWER(email)
TRIM(s)Trim spacesTRIM(customerName)
LENGTH(s)String lengthLENGTH(productName)

4.5 Null Handling Functions

FunctionDescriptionExample
COALESCE(a, b, ...)Return first non-null valueCOALESCE(discountAmount, 0)
NULLIF(a, b)Return NULL if equalNULLIF(status, 'UNKNOWN')
IFNULL(a, b)Return default if nullIFNULL(discountAmount, 0)

4.6 Aggregation Functions

FunctionDescriptionExample
SUM(x)SumSUM(salesAmount)
AVG(x)AverageAVG(unitPrice)
COUNT(*)CountCOUNT(*)
MAX(x)MaximumMAX(salesAmount)
MIN(x)MinimumMIN(salesAmount)

5. Complete Examples

5.1 Simple Arithmetic Expression

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "netAmount",
                "caption": "Net Sales Amount",
                "expression": "salesAmount - discountAmount"
            }
        ],
        "columns": ["orderId", "salesAmount", "discountAmount", "netAmount"]
    }
}

Generated SQL:

sql
SELECT
    order_id AS orderId,
    sales_amount AS salesAmount,
    discount_amount AS discountAmount,
    (sales_amount - discount_amount) AS netAmount
FROM fact_sales

5.2 Profit Rate Calculation

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "profitRate",
                "caption": "Profit Rate (%)",
                "expression": "profitAmount * 100.0 / salesAmount"
            }
        ],
        "columns": ["orderId", "salesAmount", "profitAmount", "profitRate"],
        "slice": [
            { "field": "salesAmount", "op": ">", "value": 0 }
        ]
    }
}

5.3 Chained Calculated Fields

Calculated fields can reference other calculated fields:

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "netAmount",
                "caption": "Net Sales Amount",
                "expression": "salesAmount - discountAmount"
            },
            {
                "name": "taxIncluded",
                "caption": "Tax Included Amount",
                "expression": "netAmount * 1.13"
            }
        ],
        "columns": ["orderId", "salesAmount", "netAmount", "taxIncluded"]
    }
}

5.4 Reference Dimension Columns

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "yearMonth",
                "caption": "Year-Month",
                "expression": "CONCAT(YEAR(salesDate$caption), '-', MONTH(salesDate$caption))"
            }
        ],
        "columns": ["orderId", "salesDate$caption", "yearMonth", "salesAmount"]
    }
}

5.5 Calculated Field as Filter Condition

json
{
    "param": {
        "calculatedFields": [
            {
                "name": "profitRate",
                "caption": "Profit Rate",
                "expression": "profitAmount * 100.0 / salesAmount"
            }
        ],
        "columns": ["orderId", "salesAmount", "profitAmount", "profitRate"],
        "slice": [
            { "field": "salesAmount", "op": ">", "value": 0 },
            { "field": "profitRate", "op": ">", "value": 10 }
        ]
    }
}

5.6 Calculated Fields in Grouped Aggregations

json
{
    "param": {
        "columns": [
            "product$categoryName",
            "sum(salesAmount) as totalSales",
            "sum(profitAmount) as totalProfit",
            "sum(profitAmount) * 100.0 / sum(salesAmount) as profitRate"
        ],
        "groupBy": [
            { "field": "product$categoryName" }
        ],
        "orderBy": [
            { "field": "totalSales", "order": "desc" }
        ]
    }
}

6. Security

6.1 Prohibited Functions

The following functions will be intercepted and throw SecurityException:

  • EXEC, EXECUTE
  • DROP, DELETE, UPDATE, INSERT
  • CREATE, ALTER, TRUNCATE
  • Other functions not in the whitelist

6.2 Error Handling

Error TypeDescription
Reference non-existent columnThrows exception indicating column doesn't exist
Duplicate calculated field nameThrows exception indicating name already exists
Alias conflicts with existing fieldThrows exception indicating field name conflict
Using prohibited functionThrows SecurityException

7. Best Practices

  1. Avoid division by zero: Add salesAmount > 0 condition before division
  2. Use COALESCE: Handle fields that may be NULL
  3. Naming conventions: Use meaningful names for calculated fields, avoid conflicts with existing fields
  4. Chain dependencies: Referenced calculated fields must be defined before the referencing field
  5. Performance considerations: Complex calculated fields may impact query performance

Next Steps