Core Syntax

A complete reference for SemQL syntax and clauses

SemQL is syntactically compatible with PostgreSQL. If you know PostgreSQL, you already know most of SemQL. The differences are in what you reference — semantic model names instead of physical table names — not in how you write queries.

This page covers every clause you'll use.


SELECT

Select the fields you want in the output. These can be dimensions, measures, aliases, literals, or expressions.

-- Dimensions (attributes you slice by)
SELECT name, region, created_at FROM customers

-- Measures (pre-aggregated metrics)
SELECT total_revenue, order_count FROM sales

-- With model qualifier (use when field names are ambiguous)
SELECT organizations.name, users.name FROM organizations JOIN users ...

-- Aliases
SELECT name AS organization_name, total_revenue AS revenue FROM organizations

-- Literals
SELECT name, 'active' AS status FROM organizations[active_only]

When to qualify field names: You only need to qualify (e.g. organizations.name) when the same field name exists in multiple tables you're querying. When it's unambiguous, just use the bare field name.


FROM

Reference a semantic model by name — no schema prefix, no physical table path.

Applying predefined filters

Add reusable filter conditions directly in the FROM clause using square brackets:

Filters can also appear in JOIN clauses:

Important: Filters go in FROM or JOIN — never in SELECT. See Dimensions vs. Measures for more on filters.


WHERE

Filter rows based on dimension values, before any aggregation happens.

WHERE vs. HAVING: Use WHERE to filter dimensions (raw values). Use HAVING to filter measures (aggregated results). See Dimensions vs. Measures for the full explanation.


GROUP BY

Group results by one or more dimensions. Required whenever your query mixes dimensions with measures.


HAVING

Filter groups after aggregation. Use this to filter by measure values.


ORDER BY / LIMIT

Standard SQL ordering and row limiting.


JOIN

Join multiple models together. Use the relationship fields defined in your semantic layer — check the model definitions to find the correct join keys.

Tip: Use the relationships documented in your semantic layer to find the correct join columns. Don't assume — look up the exact field names.


WITH (CTEs)

Common Table Expressions let you break complex queries into named, reusable steps. Standard SQL WITH syntax works as-is.

Note: Inside a CTE body, you're writing against semantic models normally. But once a CTE is defined, references to it are plain SQL — region in top_regions is just a column alias, not a semantic reference.


UNION / UNION ALL

Combine results from multiple queries. Both queries must return the same number of columns with compatible types.


Window Functions

Window functions let you compute running totals, rankings, and period-over-period comparisons without collapsing rows into groups.

Ranking

Running totals

Period-over-period comparisons

Partitioned windows

Supported window functions: ROW_NUMBER, RANK, DENSE_RANK, NTILE, PERCENT_RANK, CUME_DIST, LEAD, LAG, FIRST_VALUE, LAST_VALUE, NTH_VALUE


Subqueries

Standard SQL subqueries work in SemQL.


What SemQL does NOT support

  • DELETE, UPDATE, INSERT, DROP, TRUNCATE — SemQL is read-only by design

  • Schema-qualified table names like my_schema.my_table — use model names instead

  • Direct INFORMATION_SCHEMA queries

  • Bypassing auto-applied model filters — they are always active


Supported Functions

Aggregate

Function
Description

COUNT(x), COUNT(DISTINCT x)

Count rows or unique values

SUM(x)

Sum of values

AVG(x)

Average

MIN(x), MAX(x)

Minimum / maximum

STDDEV(x), VARIANCE(x)

Standard deviation / variance

STRING_AGG(x, sep)

Concatenate strings with separator

ARRAY_AGG(x)

Aggregate into an array

PERCENTILE_CONT(p), MEDIAN(x)

Percentile calculations

BOOL_AND(x), BOOL_OR(x)

Boolean aggregations

CORR(x, y)

Correlation coefficient

Reminder: Never wrap a predefined measure in an aggregate function. SUM(total_revenue) will double-aggregate. See Dimensions vs. Measures.

Date / Time

Function
Description

DATE_TRUNC('month', date)

Truncate to time period

DATE_PART('year', date)

Extract part of a date

EXTRACT(YEAR FROM date)

Extract part of a date

NOW(), CURRENT_DATE

Current timestamp / date

CURRENT_TIMESTAMP

Current timestamp with timezone

String

Function
Description

UPPER(x), LOWER(x)

Change case

LENGTH(x)

String length

TRIM(x)

Remove whitespace

SUBSTRING(x, start, len)

Extract substring

CONCAT(x, y, ...)

Concatenate strings

REPLACE(x, from, to)

Replace substring

Math

Function
Description

ABS(x)

Absolute value

ROUND(x, n)

Round to n decimal places

CEIL(x), FLOOR(x)

Round up / down

MOD(x, y)

Modulo

POWER(x, y), SQRT(x)

Exponent / square root

LEAST(x, y), GREATEST(x, y)

Minimum / maximum of arguments

Geo

Function
Description

GEO_DISTANCE(lat1, lng1, lat2, lng2)

Distance in km between two coordinates

GEO_WITHIN_RADIUS(lat1, lng1, lat2, lng2, radius_km)

True/false: is point within radius?

See Geo Functions for full documentation.

Last updated