ParaQL Language Reference
Complete syntax reference for ParaQL including SELECT, FROM, WHERE, aggregation, traversal, temporal queries, and built-in functions
This page is the definitive syntax reference for ParaQL. Every clause, operator, function, and special statement is documented here.
Basic SELECT
SELECT <columns>
FROM <source>
[WHERE <conditions>]
[GROUP BY <columns>]
[HAVING <conditions>]
[ORDER BY <column> [ASC|DESC]]
[LIMIT <n>]
[OFFSET <n>]SELECT Columns
| Syntax | Description |
|---|---|
* | All universal columns |
name | Universal field |
config.phase | Config-namespace field (type-specific) |
metrics.cpu_percent | Metrics-namespace field |
raw.metadata.labels | Raw JSONB deep path access |
COUNT(*) AS total | Aggregate with alias |
config.ram_mb / 1024 AS ram_gb | Arithmetic expression |
DISTINCT
SELECT DISTINCT namespace
FROM kubernetes.podRemoves duplicate rows from the result set.
FROM Clause
CI Types
Query a specific CI type using the source.type format:
FROM kubernetes.pod
FROM openstack.instance
FROM ceph.osdUse SHOW TABLES to list all available CI types.
Wildcard (All Types)
FROM *Queries across all CI types. Useful for cross-system searches. Note that this carries a higher complexity cost.
Special Tables
| Table | Description |
|---|---|
changes | Global change history (ci_name, change_type, changed_at, field details) |
relationships | Relationship records (source_ci_id, target_ci_id, relationship_type) |
SELECT ci_name, change_type, changed_at
FROM changes
WHERE changed_at > NOW() - INTERVAL '24 hours'
ORDER BY changed_at DESCTable Aliases
SELECT p.name, p.config.phase
FROM kubernetes.pod p
WHERE p.config.phase = 'Running'WHERE Clause
Comparison Operators
| Operator | Example |
|---|---|
= | WHERE status = 'active' |
!= | WHERE config.phase != 'Running' |
> | WHERE config.vcpus > 4 |
>= | WHERE config.ram_mb >= 1024 |
< | WHERE criticality_score < 50 |
<= | WHERE config.disk_gb <= 100 |
Pattern Matching
| Operator | Description | Example |
|---|---|---|
LIKE | Case-sensitive pattern (% = any chars, _ = single char) | WHERE name LIKE 'web-%' |
ILIKE | Case-insensitive pattern | WHERE name ILIKE '%nginx%' |
Set Operators
WHERE config.phase IN ('Pending', 'Failed', 'Unknown')
WHERE source NOT IN ('kubernetes', 'ceph')Range
WHERE changed_at BETWEEN NOW() - INTERVAL '48 hours' AND NOW()
WHERE config.vcpus BETWEEN 2 AND 8NULL Checks
WHERE namespace IS NULL
WHERE criticality IS NOT NULLStaleness
Check if a CI hasn't been seen recently:
WHERE last_seen IS STALE BY INTERVAL '2 hours'Logical Operators
Combine conditions with AND, OR, and NOT. Use parentheses for grouping:
WHERE (config.phase = 'Running' OR config.phase = 'Succeeded')
AND namespace != 'kube-system'
AND NOT name LIKE 'test-%'Automatic Active Filter
ParaQL automatically adds status = 'active' to CI queries unless you explicitly reference status in your WHERE clause. This means:
-- Implicitly filtered to active CIs only
SELECT name FROM kubernetes.pod
-- No auto-filter because status is referenced
SELECT name, status FROM kubernetes.pod WHERE status = 'inactive'Column Namespaces
Every CI has three data namespaces:
| Namespace | Access | Description |
|---|---|---|
| Universal | name, ci_type, status, source, created_at, last_seen, namespace, criticality, criticality_score | Common fields shared by all CI types |
| Config | config.phase, config.vcpus | Type-specific configuration data (tracked in change history) |
| Metrics | metrics.cpu_percent | Type-specific runtime metrics (not tracked in changes) |
| Raw | raw.metadata.labels | Deep JSONB access into the original collected data |
Use DESCRIBE kubernetes.pod to see all available columns for a CI type, grouped by namespace.
Aggregation
GROUP BY
SELECT source, COUNT(*) AS count
FROM *
WHERE status = 'active'
GROUP BY source
ORDER BY count DESCAggregate Functions
| Function | Description |
|---|---|
COUNT(*) | Count rows |
COUNT(column) | Count non-null values |
SUM(column) | Sum numeric values |
AVG(column) | Average |
MIN(column) | Minimum value |
MAX(column) | Maximum value |
HAVING
Filter aggregated results (applied after GROUP BY):
SELECT namespace, COUNT(*) AS pod_count
FROM kubernetes.pod
GROUP BY namespace
HAVING COUNT(*) > 5
ORDER BY pod_count DESCOrdering and Pagination
ORDER BY name ASC -- ascending (default)
ORDER BY criticality_score DESC -- descending
ORDER BY namespace, name -- multi-column sort
LIMIT 50 -- max rows returned
OFFSET 20 -- skip first N rowsWhen no LIMIT is specified, ParaQL applies a default limit of 1000 rows to prevent accidental full-table scans.
Scalar Functions
| Function | Description | Example |
|---|---|---|
COALESCE(a, b) | First non-null value | COALESCE(namespace, 'none') |
NULLIF(a, b) | Returns null if a = b | NULLIF(status, 'unknown') |
UPPER(col) | Uppercase string | UPPER(name) |
LOWER(col) | Lowercase string | LOWER(ci_type) |
TRIM(col) | Strip whitespace | TRIM(name) |
CONCAT(a, b, ...) | Concatenate strings | CONCAT(source, '.', ci_type) |
LENGTH(col) | String length | LENGTH(name) |
CAST(col AS type) | Type cast | CAST(config.vcpus AS float) |
DATE_TRUNC(unit, col) | Truncate timestamp | DATE_TRUNC('day', created_at) |
NOW() | Current timestamp | WHERE created_at > NOW() - INTERVAL '7 days' |
Computed Virtual Columns
These are ParaQL-specific functions that compute derived values from CI metadata:
| Function | Returns | Description |
|---|---|---|
age() | Duration | Time since CI was first created |
stale_for() | Duration | Time since CI was last seen by a collector |
last_updated() | Timestamp | Most recent change timestamp |
change_count() | Integer | Total number of changes for the CI |
change_count(INTERVAL '7 days') | Integer | Changes within the specified window |
relationship_count() | Integer | Total relationships (inbound + outbound) |
inbound_count() | Integer | Relationships pointing to this CI |
outbound_count() | Integer | Relationships from this CI to others |
SELECT name, ci_type,
age() AS ci_age,
stale_for() AS staleness,
change_count(INTERVAL '7 days') AS weekly_changes,
relationship_count() AS rels
FROM *
WHERE status = 'active'
ORDER BY weekly_changes DESC
LIMIT 20Tip: Always alias computed columns (e.g., age() AS ci_age) for readable column headers in results.
Arithmetic
Standard arithmetic operators work on numeric columns:
SELECT name,
config.vcpus,
config.ram_mb / 1024 AS ram_gb,
config.vcpus * 2 AS double_vcpus
FROM openstack.instance
WHERE status = 'active'
ORDER BY config.vcpus DESCSupported operators: +, -, *, /, % (modulo).
Intervals
Time intervals are used with temporal functions and comparisons:
INTERVAL '7 days'
INTERVAL '24 hours'
INTERVAL '30 minutes'
INTERVAL '2 hours'
NOW() - INTERVAL '7 days'Relationship Traversal
Walk the infrastructure graph using arrow syntax:
SELECT dep.name, dep.ci_type,
pod.name, pod.ci_type
FROM kubernetes.deployment dep
-[manages]-> kubernetes.pod podArrow Syntax
| Syntax | Direction | Meaning |
|---|---|---|
-[type]-> | Forward | Source runs/contains/manages target |
<-[type]- | Reverse | Target runs/contains/manages source |
-[*]-> | Wildcard type | Any relationship type |
-[*1..3]-> | Variable depth | 1 to 3 hops of any type |
Multi-Hop Traversal
Chain multiple hops to walk deep into the infrastructure stack:
SELECT node.name, node.ci_type,
vm.name, vm.ci_type,
os.name, os.ci_type
FROM proxmox.node node
<-[runs_on]- proxmox.vm vm
<-[runs_on]- os.linux osWildcard Targets
Match any CI type at the other end:
SELECT src.name, src.ci_type,
tgt.name, tgt.ci_type
FROM kubernetes.deployment src
-[*]-> * tgt
LIMIT 30Variable-Depth Traversal
Explore relationships up to N hops deep:
SELECT src.name, src.ci_type,
tgt.name, tgt.ci_type
FROM proxmox.node src
-[*1..3]-> * tgt
LIMIT 50Maximum depth is 10 hops. Cycle detection prevents infinite loops.
Filtering Traversal Results
Apply WHERE conditions to any aliased table in the traversal:
SELECT dep.name, dep.ci_type,
pod.name, pod.ci_type
FROM kubernetes.deployment dep
-[manages]-> kubernetes.pod pod
WHERE pod.config.phase = 'Running'LINEAGE (Infrastructure Stack)
Discover the full infrastructure stack above and below a CI — from physical hardware up through virtualization to application containers:
SELECT name, ci_type, tier, depth, direction
FROM LINEAGE(kubernetes.pod, name LIKE '%api%')| Column | Description |
|---|---|
name | CI name |
ci_type | CI type |
tier | Infrastructure tier (hardware, os, virtual, platform, application, service) |
depth | Hops from the seed CI |
direction | "up" (toward hardware) or "down" (toward applications) |
relationship_type | Type of relationship connecting this hop |
LINEAGE respects the tier ordering defined in the tier registry to produce a coherent stack view.
-- Lineage for a specific node
SELECT name, ci_type, tier, depth, direction, relationship_type
FROM LINEAGE(proxmox.node)IMPACT (Blast Radius)
Determine what would be affected if a CI goes down:
SELECT name, ci_type, depth, path, criticality, criticality_score
FROM IMPACT(proxmox.node, name LIKE '%pve%')
ORDER BY depth, criticality_score DESC| Column | Description |
|---|---|
name | Affected CI name |
ci_type | Affected CI type |
depth | Hops from the failed CI |
path | Relationship path from source to this CI |
criticality | Criticality tier (Critical, High, Medium, Low) |
criticality_score | Numeric criticality score (0-100) |
Impact analysis follows all relationships outward from the seed CI, building a dependency tree of everything that would break.
-- Storage failure: what depends on this pool?
SELECT name, ci_type, depth, path, criticality, criticality_score
FROM IMPACT(ceph.pool)
ORDER BY criticality_score DESC
LIMIT 50ORPHANS
Find CIs with no relationships — potential configuration drift or missing discovery:
SELECT name, ci_type, source, age() AS ci_age, last_seen
FROM ORPHANS()
WHERE status = 'active'
ORDER BY ci_age DESC
LIMIT 30You can optionally filter orphans to a specific CI type:
SELECT COUNT(*) AS orphaned_pods
FROM ORPHANS(kubernetes.pod)DIFF (Temporal Comparison)
Compare infrastructure state between two points in time:
DIFF kubernetes.pod
BETWEEN NOW() - INTERVAL '7 days' AND NOW()Results include three categories:
| Diff Type | Meaning |
|---|---|
| Added | CIs that were created in the time window |
| Removed | CIs that were deleted in the time window |
| Modified | CIs with field-level changes |
DIFF supports WHERE, ORDER BY, and LIMIT:
DIFF openstack.instance
BETWEEN NOW() - INTERVAL '30 days' AND NOW()
ORDER BY name
LIMIT 100AS OF (Point-in-Time Snapshot)
View infrastructure state as it existed at a specific point in the past:
SELECT name, config.phase, config.node_name
FROM kubernetes.pod
AS OF NOW() - INTERVAL '7 days'
WHERE config.phase = 'Running'AS OF reconstructs CI state by walking the change history backwards from the specified timestamp. This works with any standard SELECT query.
Schema Introspection
| Statement | Description |
|---|---|
SHOW TABLES | List all CI types |
SHOW TABLES FROM kubernetes | CI types from a specific source |
DESCRIBE kubernetes.pod | Column names, types, and namespaces |
SHOW RELATIONSHIPS | All relationship types with source/target |
SHOW RELATIONSHIPS FOR proxmox.node | Relationships involving a specific type |
SHOW SOURCES | All configured data sources |
SHOW TIERS | Infrastructure tier hierarchy |
EXPLAIN
Preview the execution plan without running the query:
EXPLAIN SELECT name, config.phase
FROM kubernetes.pod
WHERE config.phase = 'Running'The explain view shows the query execution plan, complexity score, and complexity breakdown. Useful for understanding query cost and optimizing performance.
Complexity System
Every query is scored for complexity before execution. This protects the database from accidentally expensive queries.
| Tier | Score Range | Behavior |
|---|---|---|
| Immediate | 0-15 | Executed immediately |
| Warning | 16-25 | Executed with a performance warning |
| Elevated | 26-40 | Requires elevated API key privileges |
| Reject | 41+ | Rejected — simplify the query |
Factors that increase complexity:
FROM *(wildcard across all types)- Relationship traversal (per hop)
- Variable-depth traversal
- IMPACT, LINEAGE, ORPHANS
- DIFF, AS OF
- Missing LIMIT clause
- Leading-wildcard ILIKE (
ILIKE '%term%')
Use EXPLAIN to inspect the complexity breakdown of any query.