Alertee LogoAlertee
SQL data quality checks

SQL checks that catch silent data failures in production Postgres & ClickHouse

Stale rows. Imports that succeed but write nothing. A dropped region or tenant hiding under a healthy total. Row counts that quietly collapse. The failures where the app stays up and the database stops being right — caught with plain SQL you can read and edit.

Postgres · ClickHouse · Read-only connection · Email, Slack, webhook · CLI & MCP

Three failures uptime monitors never see

Each is a SQL pattern, not a rule to paste in. The tables, thresholds, cadence, and business meaning differ for every team — treat these as shapes you edit for your own schema.

Stale rows

A feed or job stops, but the table stays queryable and full of yesterday's rows. Nothing errors.

Freshness: how long since the newest row?

SELECT EXTRACT(EPOCH FROM now() - max(updated_at)) / 60
        AS minutes_since_last_row
FROM orders;
-- Healthy: minutes_since_last_row < 30

An import that writes nothing

The nightly load exits zero and pings success, but an upstream change made it write no rows. The count quietly flatlines.

Row-count baseline: did today's load land anything?

SELECT count(*) AS rows_today
FROM daily_orders_import
WHERE loaded_at >= current_date;
-- Healthy (after the load window closes): rows_today > 0

A tenant or region gone dark

The overall total looks fine, so a whole-table check passes. One customer or region stopped reporting and their volume is hidden by everyone else's.

Group by entity: which slice went quiet?

SELECT tenant_id AS name,
       EXTRACT(EPOCH FROM now() - max(created_at)) / 60 AS value
FROM events
GROUP BY tenant_id
HAVING now() - max(created_at) > interval '60 minutes';
-- Any rows returned = a tenant that stopped reporting

Illustrative only. There is no copy-paste check library — the reusable part is the pattern and the reasoning, which you adapt to your tables, thresholds, and cadence.

How Alertee runs them

The query is the check. You keep it readable and editable the whole way through.

Write the SQL, or let AI draft it

Point Alertee at a read-only Postgres or ClickHouse connection. Write the query yourself, or have the AI agent inspect your schema and draft one. Either way it's plain SQL you review and edit before it runs — nothing hidden.

Set the healthy condition

Say what 'fine' looks like — rows_today > 0, minutes_since_last_row < 30 — and the interval. Alertee runs the check on its own schedule, outside your pipeline, so it still fires when the pipeline is the thing that's down.

Get one Inbox item when it breaks

A failing check opens an incident you acknowledge and resolve, with email, Slack, or webhook alerts. Classifying it real, transient, or expected feeds back so the check gets quieter, not noisier.

Where this sits

More than uptime

A ping tells you the server answers. It can't tell you the import wrote zero rows or a tenant went dark. Server up does not mean the data is correct.

Lighter than data observability

Enterprise data observability platforms are broad, expensive, and usually a rollout project. This is a few SQL checks an engineer stands up in minutes.

Honest about cron + SQL + webhook

A script and a Slack webhook genuinely works — until check count, threshold drift, and alert fatigue make it painful to own. That's the point Alertee earns its keep.

The reusable asset is the pattern and its reasoning, never a shared catalogue of thresholds.

Start with 5 checks, free

Connect a read-only database, turn on your first check, and see it catch something. No credit card required.

Free$0

5 checks, 2 connections. No card.

Starter$29

25 checks, 5 connections, 5-min intervals.

Team$99

500 checks, 50 connections, 1-min intervals.