How to send a Slack alert from a SQL query
Turn a SQL query on PostgreSQL, MySQL or MariaDB into Slack messages: one per new row, no duplicates on every run, previewed before anything posts.
- PostgreSQL
- MySQL
- MariaDB
- Slack
- how-to
- sql
- slack
You have a query that finds something your team should hear about: a declined card, a big refund, an Enterprise sign-up, an urgent ticket nobody answered. You want a Slack message for each new row it returns. Rowfire, which is open source, does exactly that for PostgreSQL, MySQL and MariaDB: the query becomes a trigger, a rule says how often one row may post, and Slack is the action. Each one is backtested and run in shadow before anything is sent.
The usual ways, and where they stop
- A cron job and a script. Run the query, loop over the rows, call Slack’s API. Quick to write. Then it posts the same rows again on the next run, so you add a table of what you already sent, then a cadence, then retries, and now it’s a service someone owns.
- An alert in your BI tool. Good for “this number crossed a threshold” and for sending a result table on a schedule. Less suited to one message per row, per customer, at most once a week. See Rowfire vs SQL alerts in a BI tool.
- Code in the application. Right for the first few. Each new request becomes an engineering ticket, and the app can’t announce something that didn’t happen. See Rowfire vs application code.
1. Write the query as a trigger
A trigger is one read-only SELECT. It can join and compute anything. Two of
its columns matter: a clock (when it happened) and a key (what counts as one
thing).
SELECT r.id AS refund_id,
a.name AS account,
r.amount,
r.reason,
r.created_at
FROM refunds r
JOIN accounts a ON a.id = r.account_id
WHERE r.amount >= 500
Here the clock is created_at and the key is refund_id. Rowfire adds the
time window itself, so you never write WHERE created_at > now() - interval '5 minutes', and it starts at now: switching it on never posts last month’s
rows.
2. Say how often one key may post
The rule is where duplicates are decided, not the query. Once per refund for this one. For a declined card you’d key by account and pick once per account per day, so three retries on one invoice post once. The options are once ever, once per day, week or month, and every nth time.
3. Attach Slack
Connect Slack with a bot token, pick the send_message action and a
channel, and write the message. Any column from the row goes in with
{{ column }}:
Refund of {{ amount }} for {{ account }}: {{ reason }}
A template that names a column the row doesn’t have fails that delivery instead of posting a message with a hole in it.
4. Backtest, shadow, then live
Before it posts anything, a backtest replays the rule over the last N days and shows how many messages it would have sent, with example rows. In the demo, the obvious “Enterprise sign-up” query would have posted 38 times; the backtest showed internal QA tenants in the rows, and the fixed query posts 26.
Then shadow mode renders every request against live data and records it without sending. When the messages look right, promote the rule to live.
The same query, for more than Slack
Many rules can subscribe to one trigger, which is polled once. The declined
card that posts to #billing daily can also
open a Zendesk ticket
weekly, or call any REST API. See
Slack and Zendesk alerts when a card is declined
for both rules on one trigger, and the use cases for queries
you can copy.
Try it in the demo: sample data and a Demo inbox, so nothing needs a Slack workspace.
Questions
Can I send a Slack message when a SQL query returns new rows?
Yes. In Rowfire the query is a trigger: one SELECT with a timestamp column and a key. Rowfire polls it, within a minute by default, and a rule posts to Slack for each new row, at most as often as you allow per key.
How do I stop the same row from alerting on every run?
Give the trigger a key (an account, an order, a ticket) and the rule a cadence: once ever, once per day, week or month, or every nth time. Rowfire records each send in a ledger and skips a key that already fired in that period.
Does it need write access to my database?
No. Triggers run as read-only queries, and Rowfire never writes to the database it reads. Give it a read-only user or a replica.
Is it real-time?
No. Triggers are polled, within a minute by default. That suits alerts, tickets and follow-ups, not messages that must arrive instantly.