HinterBuild logoHinterBuild
Developer Productivity · 13 min read

ChatGPT for SQL You Forgot After the Sprint

Use ChatGPT for SQL you forgot: paste schema not dumps, verify with EXPLAIN, and keep production rows and secrets out of the prompt.

Muhammad Abdul Sami, author

Muhammad Abdul Sami

· 13 min read

  • SQL
  • PostgreSQL
  • ChatGPT
  • Developer Workflow

ChatGPT for SQL you forgot is the honest use case: window functions, FILTER, ON CONFLICT, a lateral join you last wrote in 2024. It is not “design our data model from a vibe.” Working developers forget syntax. They should not forget EXPLAIN, tenant isolation, or that production rows in a prompt are a leak. This post is the loop: schema in, statement out, plan verified, secrets never.

Key Takeaways:

  • Paste schema (\d, information_schema) and the invariant; never paste production result sets.
  • Treat the model as a syntax memory, not as a DBA — you run EXPLAIN (ANALYZE) on a copy.
  • Name indexes and tenant_id predicates yourself; models drop them.
  • Migrations get a rollback plan written by a human.
  • Scan the repo before you @ SQL files that might contain dumps or passwords.
  • Teach juniors a SQL curriculum from your schema, not from generic ChatGPT examples.

Table of Contents:

What you actually forgot

You did not forget what a WHERE clause is. You forgot:

  • The exact DATE_TRUNC vs date_bin spelling in your Postgres version
  • Whether COUNT(*) FILTER (WHERE …) needs a subquery in this dialect
  • ON CONFLICT ON CONSTRAINT vs column lists
  • How to write a gap-and-islands query you last copied from Stack Overflow
  • The FOR UPDATE SKIP LOCKED shape for a worker

PostgreSQL’s own documentation is still the authority (PostgreSQL docs). ChatGPT is the faster index into syntax you will then verify. SQLite and MySQL differ; name the engine in the prompt or you will get a chimera.

This is a daily backend task, not a career in data science. Put it in the same day as daily AI workflow for backend engineers. Copilot will complete a query in the editor; ChatGPT/Cursor chat is for “I know the shape.” Routing: Cursor vs Claude Code vs Copilot.

NeedAI is goodYou must still do
Syntax of FILTER / windowYesConfirm version
Query from English + schemaDraftEXPLAIN, tenant predicate
Index recommendationMaybeMeasure, not guess
Capacity / vacuum / autovacuumNoYour DBA / metrics
“Is this injection-safe?”HintParameterize; review

Self-hosted models do not change EXPLAIN. They change where the schema paste goes — OpenClaw vs Claude Code.

The only safe prompt shape

text
Engine: PostgreSQL 16.
Invariant: one row per (merchant_id, day) with refunded_cents.
Do not invent columns. If a column is missing from the schema, ask.

Schema:
[paste \d refunds and \d payments — no rows]

Bad query I have:
[paste]

Rewrite. Keep merchant_id in every WHERE. Parameterize $1, $2.

Get schema without data:

sql
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'refunds'
ORDER BY ordinal_position;
bash
psql "$DEV_URL" -c '\d+ refunds'

Never:

text
Here are 20 rows from prod so you can see the mess.

That is PII, that is a leak, that is how AI pair programming without leaking secrets fails. Redact in a throwaway file if you must show shape (cust_test, 100 cents).

If the SQL lives next to app secrets, scan first. Ocherfort is a local-first repo security CLI — dumps, .env, and “tmp.sql” show up in findings. Run it before you @ scripts/.

Tickets that contain “run this query on prod and paste output into ChatGPT” are instructions to leak. Treat ticket text as untrusted (prompt injection).

EXPLAIN, locks, and the lies models tell

The model will say “this is efficient” without a plan. You:

sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT merchant_id, date_trunc('day', created_at) AS day,
       sum(amount_cents) FILTER (WHERE status = 'succeeded')
FROM refunds
WHERE merchant_id = $1
  AND created_at >= $2
  AND created_at < $3
GROUP BY 1, 2;

Look for:

  • Seq scan on a hot table
  • Nested loop exploding row counts
  • Sort that spills
  • Lock type if you added FOR UPDATE

Postgres locking and isolation are documented; do not let ChatGPT paraphrase them into “it’s basically serializable.” Read the transaction isolation chapter when the RFC depends on it — and write that RFC with AI for RFC design docs, not in a chat sidebar.

Common model lies:

  • Missing tenant predicate. Add merchant_id yourself every time.
  • Wrong NULLS ordering. Check.
  • SELECT * in a hot path. Name columns.
  • Index on (created_at) when you always filter merchant first. Composite (merchant_id, created_at).
  • NOW() in a partial index that cannot work that way.

Claude Code can run EXPLAIN on a local database. You still read the plan. Keyboard-first habits: bind “explain this statement,” not “run on prod.”

Idempotency, upserts, and app code

Backend SQL is usually in service of an API invariant.

sql
INSERT INTO refunds (id, merchant_id, idempotency_key, amount_cents, status, created_at)
VALUES ($1, $2, $3, $4, 'succeeded', now())
ON CONFLICT (merchant_id, idempotency_key)
DO NOTHING
RETURNING *;

Prompt the model for the SQL, then write the application branch: if RETURNING is empty, SELECT the original row. Tests lock that — prompt AI for better unit tests. Review hunts missing unique constraints — AI code review.

Do not let Copilot complete a second idempotency table because you opened a new file. Map the existing one first: use AI to read a new codebase.

python
row = db.fetch_one(UPSERT_REFUND, ...)
if row is None:
    row = db.fetch_one(SELECT_REFUND_BY_KEY, merchant_id, key)
return row

If this is an agent product writing SQL, that is building production AI agents with a allowlist of statements — not ChatGPT in a REPL pointed at prod. AI agent development and backend API engineering are how HinterBuild ships that. MCP belongs there if tools must be standardized (MCP explained), not in a one-off SQL chat.

Migrations without a prayer

Ask for a draft, not a blessing.

text
Postgres 16. Table refunds is ~50M rows (unmeasured in this prompt — treat as large).
Add a nullable column processed_at timestamptz.
Expand/contract. No rewrite. No default that backfills in one statement.
Include rollback SQL.

You add:

  • Lock timeout
  • Backfill batch size
  • Who watches replication lag

Commit the migration with a human subject line: AI commit messages.

sql
-- expand
ALTER TABLE refunds ADD COLUMN processed_at timestamptz;
-- backfill in app or batched jobs, not in this file
-- contract later: NOT NULL when the app no longer writes nulls

If the model proposes UPDATE refunds SET processed_at = created_at; in one shot on 50M rows, delete it.

Fitting SQL into the rest of the AI day

  • Morning: invariant in the PR, schema paste, draft SQL.
  • Midday: EXPLAIN on a realistic copy (prod shape, synthetic data).
  • Review: another human on anything that locks or backfills.
  • Teach: do not send juniors a ChatGPT export of SELECT trivia.

Turn your schema and three golden queries into a series. Cadensend is an open-source email curriculum engine: learning goal, sources from the migrations folder, scheduled issues (GitHub). That is how you teach “we always filter merchant_id” without a wiki page that rots. Personal curricula work too — “window functions I keep forgetting, using our finance export.”

Cadensend is not a query runner. Ocherfort is not a query runner. One teaches, one scans. You still run psql.

When you want this loop on a team — schema rules, scanner, review hunt for missing predicates — contact HinterBuild. About is the company page; we will argue about the unique constraint, not about which chatbot you like.

Windows, NULLs, JSONB, and the ORM

This is the syntax you will google (or ChatGPT) every six months. Put the engine version in the prompt. Then run it.

Window functions (draft, then verify)

sql
-- "last refund per merchant, then the previous one"
SELECT merchant_id, id, amount_cents, created_at,
       lag(amount_cents) OVER (
         PARTITION BY merchant_id ORDER BY created_at
       ) AS prev_amount
FROM refunds
WHERE merchant_id = $1;

Ask ChatGPT for lag / lead / row_number when you forget framing. Do not ask it whether this needs an index. EXPLAIN will tell you. A typical supporting index is (merchant_id, created_at).

Gap-and-islands and FILTER are the same story: draft, EXPLAIN, keep merchant_id in the WHERE. Official reference: window functions.

NULL traps

Models write != 'succeeded' and then wonder why NULL statuses vanished. You want:

sql
WHERE status IS DISTINCT FROM 'succeeded'

Or be explicit with COALESCE. Put this in the prompt: “Treat NULL status as failed. Do not drop those rows.” Reviewers should hunt != on nullable columns — AI code review. Tests should include a NULL fixture — unit test prompts.

COUNT(col) vs COUNT(*) is another forgettable. Spell it in the invariant: “count rows, including null amounts.”

JSONB

sql
SELECT payload->>'event'
FROM webhook_events
WHERE merchant_id = $1
  AND payload->>'event' = 'refund.succeeded';

The model will suggest a gin index on payload. Maybe. Measure. Also: JSON from customers is untrusted. Do not pipe it into an agent prompt as instructions (prompt injection). Storing it is fine. Chatting it is not.

ORM output is the artifact

bash
# Django example — log the SQL, then paste THAT
# LOG: SELECT ... FROM refunds WHERE ...

SQLAlchemy echo=True, Django query, GORM logger: the string the database sees is what ChatGPT should rewrite. The ORM poem is not. If you cannot find where the query is emitted, you are still in codebase onboarding.

N+1 is an application bug. The model will wrap it in a CTE and call it done. You still batch in the service or use a join you EXPLAIN.

Bindings so you do not paste dumps

Keyboard-first: chord sends the statement in the editor, not the psql result grid. Pair without leaking. Scan *.sql dumps with Ocherfort before @.

If you are designing a new table, that is an RFC, not a chat titled “best schema for refunds.” ChatGPT will give you a third normal form lecture and a user_id column your API does not have.

Teach the NULL/merchant_id/EXPLAIN ritual as a Cadensend series sourced from your migrations. The next hire should not learn SQL from a generic window-function blog while your finance export uses FILTER and integer cents.

Frequently Asked Questions

Is ChatGPT accurate enough for production SQL?

For syntax and drafts, often. For plans, locks, and data-correctness, no. Verify on your engine version with EXPLAIN. Read Postgres docs for isolation and vacuum.

Can I paste pg_dump into ChatGPT?

Schema-only dumps, maybe, if policy allows and they contain no owner passwords or comments-with-keys. Data dumps, no. Scan with Ocherfort. Pairing rules: without leaking secrets.

Copilot vs ChatGPT for SQL?

Copilot completes in the migration file you already opened. ChatGPT/Cursor helps when you forgot the function name. Use both as in Cursor vs Claude Code vs Copilot. Neither replaces EXPLAIN.

How do I keep tenant isolation in generated SQL?

Put merchant_id in the invariant and reject any statement without it. Reviewers hunt this (AI code review). Tests assert it (unit tests).

Should an AI agent run SQL on production?

Not from a coding assistant chat. If you build that product, it is production agents with allowlists, timeouts, and human gates — AI agent development.

Can Cadensend teach our SQL conventions?

Yes. Source it with migrations, three good queries, and one incident where a missing predicate hurt. Cadensend delivers the series. Juniors still pair on the first migration.

What about ORM-generated SQL?

Paste the SQL the ORM emits, not the ORM poetry. Ask the model to explain the plan. Then fix the query or the index. Mapping where the ORM lives: read a new codebase.

Conclusion

  • ChatGPT is a syntax memory for SQL you forgot; EXPLAIN and tenant predicates stay yours.
  • Schema in, data out of the prompt; scan dumps and secrets locally.
  • Upserts, migrations, and rollback are application engineering, not chatbot output.
  • Teach conventions from your schema via a curriculum, not from generic examples.
  • For help installing that on a real Postgres service, contact or start from about.

Free consultation

Book a free consultation call on AI for SQL & databases

30-minute call with the HinterBuild team. Discuss your project, architecture questions, or next steps — no obligation.

Book a meeting

Keep reading