SQL · live examples
SQL over a hash-keyed substrate.
OriginChain runs standard SQL directly on the same store that serves vectors, full-text, and graph hops. No sync jobs, no second engine — the rows your joins touch are the rows every other shape sees.
Projection + WHERE
easyCustomers in Pune — projection, predicate, limit.
POST /v1/tenants/:t/sql { "sql": "SELECT customer_id, name, city, segment FROM customers WHERE city = 'Pune' LIMIT 5" }
INNER JOIN
easyCustomers joined to the accounts they own.
POST /v1/tenants/:t/sql { "sql": "SELECT c.name, a.account_id, a.type, a.balance_inr FROM customers c JOIN accounts a ON a.customer_id = c.customer_id WHERE c.segment = 'premium' LIMIT 5" }
GROUP BY aggregate
easyTransaction volume per account type — SUM, COUNT, GROUP BY.
POST /v1/tenants/:t/sql { "sql": "SELECT a.type, COUNT(t.txn_id) AS txns, SUM(t.amount_inr) AS volume_inr FROM transactions t JOIN accounts a ON a.account_id = t.from_account GROUP BY a.type" }
Portfolio snapshot — COUNT DISTINCT
easyThe one-line exec question: how many customers, accounts, and cities are we looking at?
POST /v1/tenants/:t/sql { "sql": "SELECT COUNT(DISTINCT c.customer_id) AS customers, COUNT(a.account_id) AS accounts, COUNT(DISTINCT c.city) AS cities FROM customers c JOIN accounts a ON a.customer_id = c.customer_id" }
LEFT JOIN with empty side
intermediateAccounts that have never transacted — the NULL side of a LEFT JOIN.
POST /v1/tenants/:t/sql { "sql": "SELECT a.account_id, a.type, t.txn_id FROM accounts a LEFT JOIN transactions t ON t.from_account = a.account_id WHERE t.txn_id IS NULL LIMIT 5" }
Self-join
intermediatePairs of customers sharing an employer — the classic self-join.
POST /v1/tenants/:t/sql { "sql": "SELECT c1.name AS a, c2.name AS b, c1.employer FROM customers c1 JOIN customers c2 ON c1.employer = c2.employer AND c1.customer_id < c2.customer_id LIMIT 5" }
Three-way join + date range
intermediateCustomers → accounts → transactions in one query: who moved the most money in Q2, by segment.
POST /v1/tenants/:t/sql { "sql": "SELECT c.segment, c.name, COUNT(t.txn_id) AS txns, SUM(t.amount_inr) AS moved_inr FROM customers c JOIN accounts a ON a.customer_id = c.customer_id JOIN transactions t ON t.from_account = a.account_id WHERE t.ts BETWEEN '2026-04-01' AND '2026-06-30' GROUP BY c.segment, c.name ORDER BY moved_inr DESC LIMIT 5" }
IN subquery — flagged-account exposure
intermediateUncorrelated subquery: every customer whose account sent money to an account that appears in the fraud-flag list.
POST /v1/tenants/:t/sql { "sql": "SELECT DISTINCT c.customer_id, c.name FROM customers c JOIN accounts a ON a.customer_id = c.customer_id JOIN transactions t ON t.from_account = a.account_id WHERE t.to_account IN (SELECT account_id FROM flags WHERE reason = 'mule_suspect')" }
Conditional aggregate + HAVING
intermediateRisk mix per segment — SUM(CASE …) pivots inside the aggregate, HAVING filters the groups.
POST /v1/tenants/:t/sql { "sql": "SELECT c.segment, COUNT(*) AS customers, SUM(CASE WHEN a.balance_inr < 0 THEN 1 ELSE 0 END) AS in_debt, AVG(a.balance_inr) AS avg_balance FROM customers c JOIN accounts a ON a.customer_id = c.customer_id GROUP BY c.segment HAVING COUNT(*) > 10" }
Dormant high-value customers
intermediateChurn-risk radar: balances over 5 lakh with no transaction in 90 days — join, subquery exclusion, threshold.
POST /v1/tenants/:t/sql { "sql": "SELECT c.customer_id, c.name, a.balance_inr FROM customers c JOIN accounts a ON a.customer_id = c.customer_id WHERE a.balance_inr > 500000 AND a.account_id NOT IN (SELECT from_account FROM transactions WHERE ts >= '2026-04-07') ORDER BY a.balance_inr DESC LIMIT 5" }
Monthly trend — GROUP BY month
intermediateTransaction volume by calendar month — the chart every ops review opens with, straight from GROUP BY.
POST /v1/tenants/:t/sql { "sql": "SELECT SUBSTR(t.ts, 1, 7) AS month, COUNT(*) AS txns, SUM(t.amount_inr) AS volume_inr FROM transactions t GROUP BY SUBSTR(t.ts, 1, 7) ORDER BY month" }