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 chart
  • day → dates along the X-axis
  • linespeed → 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


✨ Start simple, name your columns, then add filters and grouping as your questions get more specific.