Docs · Guides

Scheduled SQL queries.

Run SQL on a schedule against your own Canadian databases — a nightly rollup, an hourly sync, a reconciliation job — reading and writing your project Postgres databases directly, with no external ETL tool and no data leaving Canada.

A scheduled query is SQL plus a cron schedule. On each tick Canner runs the SQL for you in Montreal and records the result. The SQL is free-form: it can SELECT, or CREATE TABLE, INSERT, UPDATE, MERGE — whatever the job needs. This is the SQL counterpart to a scheduled job, which instead calls a webhook in your app.

Reference your databases by name

A scheduled query can reach any project database your account owns, referenced by its project slug — project.schema.table (the schema is usually public). There is no dropdown and no "attach" step: name a database in the SQL and Canner connects you to it, for reads and writes. Because you can name more than one, a single query can join or move data across projects. (A hyphen in a slug becomes an underscore in the name — project my-shop is my_shop.public.table.)

Where results go

Nothing is materialised for you — the SQL decides. Qualify a table with a project and it lands in that project's real Postgres database, where your app can read it:

-- Nightly rollup written into your project's own Postgres.
CREATE OR REPLACE TABLE shop.public.daily_sales AS
SELECT date_trunc('day', created_at) AS day,
       count(*)                      AS orders,
       sum(amount)                   AS revenue
FROM shop.public.orders
GROUP BY 1;

A cross-project example — join two databases you own and append to a third:

-- Join two projects you own and append the result to a third.
INSERT INTO warehouse.public.customer_orders
SELECT o.id, o.amount, c.segment
FROM shop.public.orders o
JOIN crm.public.customers c ON c.id = o.customer_id
WHERE o.created_at >= now() - interval '1 day';

A plain SELECTthat writes nothing is still valid; its result is logged as a small preview and then discarded. If a result isn't captured by the SQL, it's gone — like a query at a database prompt.

Create one

Go to Compute → Scheduled queries → New scheduled query and fill in three things: a name, the SQL, and a schedule. That's the whole form.

The schedule

Schedules use standard 5-field cron — minute hour day-of-month month day-of-week — and all times are UTC. The picker offers Simple (hourly / daily / weekly) or a raw cron expression.

0 5 * * *      # every day at 05:00 UTC
0 * * * *      # every hour, on the hour
*/30 * * * *   # every 30 minutes
0 6 * * 1      # every Monday at 06:00 UTC

Runs, history & cancelling

Open a query to see its run history — each run is Succeeded, Failed, Timeout, or Cancelled. You can Run now to test without waiting for the next tick, Pause and resume a query, and cancel a run that is still queued or running. Each run is bounded by a timeout; a query that overruns is recorded as a timeout.

How a run is isolated

Each run executes in an isolated, in-memory SQL engine with a per-run memory cap and timeout, and with local filesystem access disabled — a query can reach your Postgres databases over the network but cannot read or write files on the host. It can only see databases your own account owns; another tenant's data is never reachable. Everything runs in Montreal; nothing about the query or its results leaves Canada.

Plans

Scheduled queries are available on every plan. Plans differ by execution priority — best-effort on Starter, prioritised on Live, dedicated capacity on Dedicated. See Plans & limits. To explore or transform uploaded files with SQL instead, see Data Workshop.