Tabular operators
Tabular operators
Every operator that takes rows in and gives rows out.
Tabular operators are the things that follow a |. They compose in any order that makes sense.
| Operator | Does | Example |
|---|---|---|
where | Keeps matching rows | | where status >= 500 |
extend | Adds a computed column | | extend slow = latency > 1000 |
project | Keeps only these columns, in this order | | project _time, service, latency |
project-away | Drops these columns, keeps the rest | | project-away message, region |
summarize | Aggregates, optionally grouped | | summarize count() by service |
distinct | Unique combinations of these columns | | distinct service, region |
order by / sort by | Sorts, desc by default | | order by latency desc |
top | order by and take in one | | top 10 by latency desc |
take / limit | First N rows, unordered unless you sorted | | take 100 |
count | Collapses to a single count row | | count |
join | Joins another dataset on a key | | join ['deploys'] on service |
parse | Pulls fields out of a string | | parse message with "pool " size "/" cap |
render | Hints the chart type for the console | | render timechart |
where
Comparisons are == != > >= < <=, plus =~ for case-insensitive string equality. Combine with and / or. Membership is in (…) and its negation !in (…).
LSQL
read top to bottom
1['api-gateway-prod']2| where level in ("error", "warn")3| where service != "health-check"4| where route startswith "/v1/"5| take 20Two wheres or one and?
Identical in cost — the planner folds consecutive
where lines together. Use whichever reads better; separate lines are easier to comment out while debugging.summarize
summarize collapses rows into one row per group. Without by you get exactly one row. Aliases are optional but make the output readable.
LSQL
read top to bottom
1['api-gateway-prod']2| summarize3 requests = count(),4 errors = countif(status >= 500),5 p50 = percentile(latency, 50),6 p95 = percentile(latency, 95)7 by service8| extend error_rate = round(100.0 * errors / requests, 2)9| order by error_rate descjoin
Joins a second dataset on a shared key. The left side should be the smaller one — usually the aggregate you just built.
LSQL
read top to bottom
1['deploys']2| where _time > ago(1d)3| project service, version, deployed_at = _time4| join kind=inner ['api-gateway-prod'] on service5| summarize errors = countif(status >= 500) by service, version6| order by errors desckind= | Keeps |
|---|---|
inner | Rows present on both sides (default) |
leftouter | All left rows; right columns null when unmatched |
leftanti | Left rows with no match on the right — the "what is missing" join |
leftanti is the one you will reach for
"Which services deployed today have no errors" and "which orders never got a confirmation" are both
leftanti. It is the join people forget exists and then hand-roll badly.