Getting Started with OQL 🚀
Version: 1.0.0
OQL (Oden Query Language) lets you ask questions about your factory data in plain, SQL-like queries. You do not need to know where data is stored or how it is connected — OQL handles that for you.
This guide shows how to write a first query and introduces the main building blocks.
Anatomy of an OQL Query
Every OQL query starts with **aggregate**. You list what you want to measure, when to look, and optionally how to break results into rows:
[with helper as (...)]
aggregate <what you want to measure> as <column name>
[from helper]
where time from <start> to <end>
and <filters>
group by <break down by>, bucket <time step> as <time column name>
order by <column name> [desc]
having <filters on totals>
[limit n] [offset n]
settings backend = v1
You do not need every line above. Start with a time range and one measurement, then add filters and grouping as needed. See the Syntax Reference for details.
Tip: Give every calculated column and every group by column a short name with as. That makes charts, tables, and order by much easier to read.
Your first queries
One number for the whole organization — OEE over the last 30 days:
aggregate aggregation.oee as oee
where time from now()-30D to now()
One row per line — add a factory filter and group by line name:
aggregate aggregation.oee as oee
where time from now()-30D to now()
and factory.name = 'Factory A'
group by line.name as linename
Sort best lines first — order by the column name you chose:
aggregate aggregation.oee as oee
where time from now()-30D to now()
and factory.name = 'Factory A'
group by line.name as linename
order by oee desc
Visualizing in Dashboards
Dashboard charts usually need a value, a time bucket, and optionally a label (such as line name):
aggregate
avg(metric_group('linespeed_uuid')) as linespeed
where time from now()-14D to now()
group by line.name as linename, bucket 1D as day
Note
linename→ each line becomes its own series on the chartday→ dates along the X-axislinespeed→ the value on the Y-axis
Working with helper queries (CTEs)
When a question needs two steps — for example, hourly totals, then a daily average — put the first step in a **with** block and read from it with **from**:
with hourly_totals as (
aggregate
sum(metric_group('linespeed_uuid')) as total
where time from now()-7D to now()
group by line.name as linename, bucket 1h as hour
)
aggregate
avg(hourly_totals.total) as avg_hourly_total
from hourly_totals
group by linename
See the FROM Clause for more patterns.
Next Steps
- Read the Syntax Reference for syntax, clauses, and limitations
- Explore the OQL Functions Reference
- Check OQL Expressions Reference for line, run, product, and KPI fields
- Configure caching and timezone with Settings
- Learn about Window Functions for rolling totals and comparisons to previous rows
- Learn about the FROM Clause for multi-step queries
- Write and test queries in OQL Tester or Forge
✨ Start simple, name your columns, then add filters and grouping as your questions get more specific.