ArcFlow
Company
Managed Services
Markets
  • News
  • LOG IN
  • GET STARTED

OZ brings Visual Intelligence to physical venues, a managed edge layer that lets real-world environments see, understand, and act in real time.

Talk to us

ArcFlow

  • World Models
  • Sensors

Managed Services

  • OZ VI Venue 1
  • Case Studies

Markets

  • Sports
  • Broadcasting
  • Robotics

Company

  • About
  • Technology
  • Careers
  • Contact

Ready to see it live?

Talk to the OZ team about deploying at your venues, from a single pilot match to a full regional rollout.

Schedule a deployment review

© 2026 OZ. All rights reserved.

LinkedIn
ArcFlow Docs
Start
  • Quickstart
  • Installation
  • Bindings
  • Platforms
  • Get Started
  • Cookbook
Concepts
  • World Model
  • Graph Model
  • Evidence Model
  • Observations
  • Confidence & Provenance
  • Proof Artifacts & Gates
  • SQL vs GQL
  • Graph Patterns
  • Parameters
  • Query Results
  • Persistence & WAL
  • Snapshot-Pinned Reads
  • Error Handling
  • Execution Models
  • Causal Edges
  • Adapter Discipline
  • Time Decay
  • Layers
  • 1. World Store
  • 1a. World Store · Smart Reader
  • 2. Perception Lake
  • 3. World Graph
  • 4. Query Engine
  • 5. Live Surface
  • 6. Event Bus
  • 7. Behavior Engine
  • 8. Algorithm Library
  • Virtual Computed Columns
  • Threading Model
  • Typed ID Contract
WorldCypher
  • Overview
  • Execution Options
  • Statements
  • MATCH
  • WHERE
  • RETURN
  • OPTIONAL MATCH
  • CREATE
  • SET
  • MERGE
  • DELETE
  • REMOVE
  • Composition
  • WITH
  • UNION
  • UNWIND
  • CASE
  • Schema
  • Schema Overview
  • Indexes
  • Constraints
  • Functions
  • Built-in Functions
  • Aggregations
  • Procedures
  • Shortest Path
  • EXPLAIN
  • PROFILE
  • Temporal Queriesfacet
  • Spatial Queriesfacet
  • Algorithmsfacet
  • Triggers
Capabilities
  • Live Queries
  • Vector Search
  • Trusted RAG
  • Spatial Knowledge
  • Temporal
  • Behavior Graphs
  • Graph Algorithms
  • Skills
  • CREATE SKILL
  • PROCESS NODE
  • REPROCESS EDGES
  • Sync
  • Programs
  • GPU Acceleration
  • Agent-Native
  • MCP Server
  • Event Sourcing
  • Intent Relay
  • Event Bus
Use Cases
  • Agent Tooling
  • Trusted RAG
  • Knowledge Management
  • Behavior Graphs
  • Autonomous Systems
  • Physical AI
  • Digital Twins
  • Robotics & Perception
  • Sports Analytics
  • Grounded Neural Objects
  • Fraud Detection
Walkthroughs
    Guides
  • Agent Integration
  • Building a World Model
  • Modeling a Social Graph
  • Build a RAG Pipeline
  • Using Skills
  • Behavior Graphs
  • Swarm & Multi-Agent
  • Fleet Coordination
  • Migrate from Cypher / Neo4j
  • From SQL to GQL
  • Filesystem Workspace
  • Data Quality
  • Code Intelligence
  • Scale Patterns
  • v0.7 → v0.8 Lakehouse Fast-Path
  • Tutorials
  • Knowledge Graph
  • Entity Linking
  • Vector Search
  • Graph Algorithms
  • Recipes
  • CRUD
  • Multi-MATCH
  • MERGE (Upsert)
  • Full-Text Search
  • Batch Projection
  • Multi-Source Observation
  • Sports Analytics
Operations
  • CLI
  • REPL Commands
  • Snapshot & Restore
  • Filesystem Projection
  • Plugin Management
  • Agent Governance
  • Server Modes & PG Wire
  • Persistence (ops)
  • Import & Export
  • Deployment
  • Deployment Modes
  • Daemon (UDS)
  • Why not Docker
  • Architecture
  • Engine Architecture
  • Cloud Architecture
  • Sync Protocol (Deep Dive)
  • World Graph Substrate (Preview)
Reference
  • TypeScript API
  • Glossary
  • Naming & Domain Map
  • Data Types
  • Operators
  • Error Codes
  • GQL Reference
  • Known Issues
  • Versioning
  • Licensing
  • Conformance
  • GQL Conformance
  • openCypher TCK
  • Extension Regressions
GQL Reference
    Conformance
  • Conformance Dashboard
  • openCypher TCK Results
  • Extension Regressions
  • Features
  • MATCH Basic
  • CREATE Nodes Edges
  • SET REMOVE Properties
  • DELETE Detach DELETE
  • RETURN WITH WHERE
  • Order BY Limit Skip
  • Order BY Nulls First Last
  • UNWIND
  • Aggregate Functions
  • OPTIONAL MATCH
  • Variable Length Paths
  • Label OR AND NOT Expressions
  • Label Wildcard
  • Quantified Path Sugar
  • Path Modes Walk Trail Simple Acyclic
  • Shortest Path Variants
  • IS Labeled Predicate
  • Element ID Function
  • IS Type Predicate
  • Binary Literals
  • Line Comments Solidus
  • Line Comments Minus
  • GQLSTATUS Result Codes
  • GQL Error Code Mapping
  • Transaction Control Syntax
  • SET Session
  • Conditional Execution WHEN THEN ELSE
  • RETURN NEXT Pipeline
  • Primary Key Constraint
  • Unique Constraint
  • Deterministic MERGE Via PK
  • Undirected Edge MATCH
  • Cast Type Conversion
  • GQL Directories
  • Multiple Labels Per Node
  • GQL Flagger
  • NEXT Linear Composition
  • Cardinality Function
  • INT64 BIGINT Type Names
  • FLOAT64 Double Type Names
  • Log10 Log2 Functions
  • Trim Leading Trailing Both
  • FILTER Clause
  • LET Statement
  • Group BY Explicit
  • EXCEPT SET Operations
  • INTERSECT SET Operations
  • ALL Different Predicate
  • Same Predicate
  • Property Exists Function
  • Path Variable Binding
  • USE Graph Clause
  • FOR IN List
  • Typed Temporal Literals
  • Session SET Value Params
  • Typed List Annotations
  • arcflow.cosine() function
  • arcflow.embed() function
  • arcflow.similar() procedure
  • arcflow.graphrag() procedure
  • ArcFlow Extensions
  • LIVE Queries
  • Triggered Write-Back Views
  • Evidence Algebra
  • Relationship Skills
  • AI Function Namespace
  • Graph Embedding Algorithms
  • ASOF JOIN
  • Durable Workflows
  • Incremental Z-Set Engine
  • GPU GraphBLAS
  • Triggers
  • HNSW Vector Index
  • Extensions Moat

SQL vs GQL — The Mental Model Shift

SQL and GQL solve different problems. SQL is excellent at what it was designed for: structured, normalized data in well-defined tables. GQL is excellent at what SQL was never designed for: data where the relationships between things are as important as the things themselves.

This page is about the mental model shift, not the syntax. If you understand the difference in thinking, the syntax follows naturally.

The fundamental difference#

SQL asks: which rows satisfy this condition?

SELECT name, age FROM people WHERE age > 30

GQL asks: which structures exist in this graph?

MATCH (p:Person)-[:WORKS_AT]->(c:Company)
WHERE p.age > 30
RETURN p.name, c.name

SQL operates on tables. GQL operates on patterns. The difference becomes most visible when relationships are involved.

The JOIN problem#

In SQL, relationships between entities are represented as foreign keys. To traverse them, you JOIN tables. One relationship = one JOIN. Two relationships = two JOINs. A five-hop path requires five JOINs — and SQL query planners weren't built for this.

"Who are Alice's second-degree connections?"

-- SQL: explicit joins for each hop
SELECT DISTINCT p3.name
FROM people p1
JOIN knows k1 ON p1.id = k1.from_id
JOIN people p2 ON k1.to_id = p2.id
JOIN knows k2 ON p2.id = k2.from_id
JOIN people p3 ON k2.to_id = p3.id
WHERE p1.name = 'Alice'
  AND p3.id != p1.id;
-- GQL: describe the path, not the join mechanics
MATCH (alice:Person {name: 'Alice'})-[:KNOWS*2]->(connection)
RETURN DISTINCT connection.name

The SQL query is procedural: you're describing how to traverse the data. The GQL query is declarative: you're describing what shape you're looking for. As the number of hops increases, SQL scales poorly — the GQL query changes by one character (*2 becomes *3).

Schema: required vs optional#

SQL requires a schema before you can store data. Every column must be declared with a type. Adding a new attribute means an ALTER TABLE. Changing a relationship between entities may require new junction tables and migrations.

GQL is schema-optional. You can create a node with any properties at any time:

-- These can coexist without any schema definition
CREATE (n:Person {name: 'Alice', age: 30})
CREATE (n:Person {name: 'Bob', email: 'bob@co.com', verified: true})
CREATE (n:Person {name: 'Carol', company: 'Acme', title: 'Engineer', linkedin: '...'})

Different nodes with the same label can have different properties. The graph adapts to your data rather than forcing your data into a fixed shape. CALL db.schema() gives you the emergent schema when you need it.

Modeling relationships: JOINs vs first-class edges#

In SQL, a many-to-many relationship requires a junction table. Every relationship type you need = a table to manage.

-- SQL: three tables to represent "person likes movie"
CREATE TABLE people (id, name, ...);
CREATE TABLE movies (id, title, ...);
CREATE TABLE likes (person_id, movie_id, liked_at);  -- junction table

In GQL, relationships are first-class. They exist between nodes directly and can carry their own properties:

-- GQL: relationship with properties, no junction table
CREATE (alice:Person {name: 'Alice'})
CREATE (film:Movie {title: 'Arrival'})
CREATE (alice)-[:LIKES {since: '2024-01', rating: 9}]->(film)

As data complexity grows — more entity types, more relationship types, more properties — the SQL approach requires progressively more tables, more JOINs, and more careful schema design. The GQL approach stays proportional to what you're actually modeling.

Queries that are natural in GQL and awkward in SQL#

"Find all fraud rings" (circular transactions):

-- SQL: CTEs required, becomes unwieldy beyond 3 hops
WITH RECURSIVE paths AS (
  SELECT from_account, to_account, ARRAY[from_account] AS visited, 1 AS depth
  FROM transactions
  UNION ALL
  SELECT p.from_account, t.to_account, p.visited || t.from_account, p.depth + 1
  FROM paths p JOIN transactions t ON p.to_account = t.from_account
  WHERE NOT t.from_account = ANY(p.visited) AND p.depth < 10
)
SELECT * FROM paths WHERE to_account = from_account;
-- GQL: pattern describes the ring directly
MATCH (a:Account)-[:SENT*2..10]->(a)
RETURN a.id

"Find mutual connections between two people":

-- SQL: correlated subquery or triple join
SELECT p.name
FROM people p
WHERE p.id IN (
  SELECT k1.to_id FROM knows k1 WHERE k1.from_id = alice_id
) AND p.id IN (
  SELECT k2.to_id FROM knows k2 WHERE k2.from_id = bob_id
);
-- GQL: bidirectional pattern
MATCH (alice:Person {name: 'Alice'})-[:KNOWS]->(mutual)<-[:KNOWS]-(bob:Person {name: 'Bob'})
RETURN mutual.name

"Shortest path between two entities":

-- SQL: recursive CTE, complex, slow on large data
-- (omitted for brevity — it's ~20 lines and requires careful cycle detection)
-- GQL: one function
shortestPath (alice:Person {name: 'Alice'}), (bob:Person {name: 'Bob'})

Where SQL is still better#

GQL is not a replacement for SQL everywhere. SQL excels at:

  • Large-scale aggregations on flat data — GROUP BY over millions of uniform rows
  • Complex set operations — INTERSECT, EXCEPT, UNION across structured tables
  • Strict schema enforcement — when your data model is fixed and well-known
  • Reporting and BI tooling — the ecosystem around SQL is massive

The decision is about your data and your questions. If your data is naturally relational — connected entities where the connections themselves carry meaning — GQL fits. If your data is naturally tabular — facts about homogeneous things — SQL fits.

ArcFlow bridges both: the PostgreSQL wire protocol means your SQL tooling connects directly, and window functions (LAG, LEAD, STDDEV_POP, PERCENT_RANK) bring time-series analytics into the same database.

The practical starting point#

You don't need to rewrite everything. Start with the question that SQL struggles with — the one that requires five JOINs or a recursive CTE — and write it as a graph pattern. That's where GQL pays off immediately.

-- Start with what SQL makes hard
MATCH (a:Account)-[:TRANSFERRED_TO*1..5]->(b:Account)
WHERE a.flagged = true
RETURN b.id, b.owner, count(*) AS connection_count
ORDER BY connection_count DESC
LIMIT 20

Further reading#

  • Graph Patterns — how to write patterns
  • From SQL to GQL — connecting your existing SQL tools to ArcFlow
  • Migration Guide — moving an existing graph workload into ArcFlow
  • GQL Conformance — the standards story
Try it
Open ↗⌘↵ to run
Loading engine…
← PreviousProof Artifacts & GatesNext →Graph Patterns