VanaAPI

← Writing

A SQL debugging session without production rows

Daily workEN2026-10-26

A monthly report counts some customers twice. You want help with the query, not an upload of the customer table. For this walkthrough, keep the database local and prepare a small, invented example that reproduces the mistake. The working rule is simple: send the structure needed to reason about SQL, not the records behind the report.

§ Step 1: Define the question before collecting context

Write down the database engine, version, intended result, and observed behavior. Be specific about the output grain: one row per customer, order, or month. For this example, the requirement is one row per customer with their total paid order value, including customers with no paid orders.

Set a sharing boundary before opening the assistant: no production rows, credentials, connection strings, or unrestricted database tools. Check that your organization permits the chosen service and review the applicable retention, logging, and downstream-provider terms. Do not treat a redacted prompt as permission to bypass those requirements.

§ Step 2: Reduce the schema to its essentials

Prepare only the relevant table definitions. Use neutral names such as customers, orders, and order_items. Keep column types, primary keys, foreign keys, nullability, and relevant indexes. Leave unrelated tables out.

For the example, describe customers(customer_id), orders(order_id, customer_id, status, total), and order_items(item_id, order_id). State that one order can have several items. Keep any mapping from neutral names to internal names local.

Renaming is not anonymization. Replacing identifiers while retaining real records can leave people identifiable through additional information. Prefer invented records rather than assuming masked production data is safe to share. ([ico.org.uk](https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/data-sharing/anonymisation/introduction-to-anonymisation/?search=mapping+the+concept+of+the+spectrum&utm_source=openai))

§ Step 3: Invent a tiny failing dataset

Create two fictional customers. Give the first one paid order worth 30 and two order items. Give the second no orders. The expected report contains totals of 30 and zero. This creates an explicit test for accidental multiplication when joining orders to items.

Add edge cases only when they matter: an unpaid order, a null optional field, or two orders with the same total. That last case helps test proposed fixes that use DISTINCT. Do not generate the fixture by copying a few real rows and changing their names.

§ Step 4: Send a bounded request

In an approved client, configure Vana API's endpoint as the base URL. Its published address is https://api.vanaapi.com. Create an account when you are ready to try this workflow. ([vanaapi.com](https://vanaapi.com/))

Keep the API key outside the prompt and repository, using a server-side environment variable or secret manager. Official OpenAI guidance likewise recommends keeping API credentials secret and loading them server-side. ([developers.openai.com](https://developers.openai.com/api/reference/overview?utm_source=openai))

Send the reduced schema, synthetic fixture, sanitized query, and this instruction:

Review this PostgreSQL query using only the supplied synthetic example. Explain why totals repeat. Return a corrected query, its assumptions, and tests for customers without orders. Preserve one row per customer. Do not request production records or execute anything.

§ Step 5: Review the proposed correction

For this fixture, look for a correction that removes the unnecessary item join or aggregates at the intended grain before joining. Ask the assistant to explain each join and filter. Reject a cosmetic DISTINCT fix unless it also passes the two-equal-orders test.

Require parameter placeholders instead of real account identifiers or dates. Check that the revised query preserves unpaid-order rules, missing-customer behavior, and tenant boundaries.

§ Step 6: Validate locally with limited access

Run the candidate against the synthetic fixture first. Then follow your normal review process in an approved environment, using a restricted role and a statement timeout. If PostgreSQL row security matters, test with the application role: table owners normally bypass those policies. ([postgresql.org](https://www.postgresql.org/docs/18/ddl-rowsecurity.html?utm_source=openai))

For performance investigation, start with EXPLAIN and inspect its output locally before sharing anything. EXPLAIN ANALYZE actually executes the statement, so reserve it for an explicitly approved test. ([postgresql.org](https://www.postgresql.org/docs/16/sql-explain.html?utm_source=openai))

§ Step 7: Keep follow-ups inside the same boundary

Return only a sanitized error, revised synthetic case, or reviewed plan excerpt. Check comments, literals, filenames, and diagnostic output before sending. Save the accepted query and regression tests locally. The useful outcome is a verified SQL change and a reusable debugging fixture, without making production records part of the conversation.