Text-to-SQL examples

Text-to-SQL Examples

Natural-language prompts and the SQL they produce — from simple SELECTs to grouping, updates, views, and functions.

Examples use PostgreSQL syntax. The same prompts and patterns apply across all 28 supported databases — MySQL, SQL Server, Oracle, BigQuery, Snowflake, and more.

Basic SQL generations

Generate basic SQL queries, e.g. SELECT queries with clauses and JOINs.

1. Get customers
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email,
  c.active,
  c.create_date,
  a.address,
  a.address2,
  a.district,
  a.postal_code,
  a.phone,
  ci.city AS city,
  co.country AS country
FROM customer c
LEFT JOIN address a ON c.address_id = a.address_id
LEFT JOIN city ci ON a.city_id = ci.city_id
LEFT JOIN country co ON ci.country_id = co.country_id
ORDER BY c.customer_id;
2. Get customers created past month
SELECT
  customer_id,
  first_name,
  last_name,
  email,
  create_date
FROM
  customer
WHERE
  create_date >= CURRENT_TIMESTAMP - INTERVAL '1 month'
  AND create_date IS NOT NULL
ORDER BY
  create_date DESC;
3. Get customers created past month and limit it 20
SELECT
  *
FROM
  customer
WHERE
  create_date >= now () - interval '1 month'
ORDER BY
  create_date DESC
LIMIT
  20;
4. Get customers created past month and group by email domain
SELECT
  COALESCE(
    NULLIF(lower(split_part (email, '@', 2)), ''),
    '(no_domain)'
  ) AS domain,
  COUNT(*) AS customer_count,
  ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 2) AS pct_of_period
FROM
  customer
WHERE
  create_date >= now () - interval '30 days'
GROUP BY
  COALESCE(
    NULLIF(lower(split_part (email, '@', 2)), ''),
    '(no_domain)'
  )
ORDER BY
  customer_count DESC;
5. Get customers created past month who haven't made a purchase yet
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email,
  c.create_date
FROM customer c
WHERE c.create_date >= now() - interval '1 month'
  AND NOT EXISTS (
    SELECT 1
    FROM payment p
    WHERE p.customer_id = c.customer_id
  )
ORDER BY c.create_date DESC;
6. Get customers who made more than 3 purchases last year and who lives in New York
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email,
  COUNT(p.payment_id) AS purchases_last_year
FROM
  customer c
  JOIN address a ON c.address_id = a.address_id
  JOIN city ci ON a.city_id = ci.city_id
  JOIN payment p ON p.customer_id = c.customer_id
WHERE
  ci.city ILIKE 'New York'
  AND p.payment_date >= (
    date_trunc ('year', current_date) - interval '1 year'
  )
  AND p.payment_date < date_trunc ('year', current_date)
GROUP BY
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email
HAVING
  COUNT(p.payment_id) > 3
ORDER BY
  purchases_last_year DESC;
7. Get customer with email john@doe.org
SELECT
  customer_id,
  first_name,
  last_name,
  email,
  active,
  address_id,
  create_date,
  last_update,
  store_id
FROM customer
WHERE email = 'john@doe.org';

Advanced SQL generations

Generate more advanced SQL queries, e.g. queries with complex logic.

1. Get customers within 500m of the Eiffel Tower using lat/lng (using PostGIS extensions)
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  a.address,
  a.postal_code,
  a.latitude,
  a.longitude,
  ST_Distance(
    ST_SetSRID(ST_MakePoint(a.longitude, a.latitude), 4326)::geography,
    ST_SetSRID(ST_MakePoint(2.2945, 48.8584), 4326)::geography
  ) AS distance_m
FROM customer c
JOIN address a ON c.address_id = a.address_id
WHERE a.latitude IS NOT NULL
  AND a.longitude IS NOT NULL
  AND ST_DWithin(
    ST_SetSRID(ST_MakePoint(a.longitude, a.latitude), 4326)::geography,
    ST_SetSRID(ST_MakePoint(2.2945, 48.8584), 4326)::geography,
    500
  )
ORDER BY distance_m;
2. Get customers who didn't make a purchase in the last 12 months but a purchase in the 12 months before that
SELECT c.customer_id,
       c.first_name,
       c.last_name,
       c.email
FROM customer c
WHERE EXISTS (
    SELECT 1
    FROM payment p
    WHERE p.customer_id = c.customer_id
      AND p.payment_date >= now() - interval '24 months'
      AND p.payment_date <  now() - interval '12 months'
)
AND NOT EXISTS (
    SELECT 1
    FROM payment p2
    WHERE p2.customer_id = c.customer_id
      AND p2.payment_date >= now() - interval '12 months'
);
3. Update all customers starting with a vowel to also start their last name with that vowel
UPDATE customer
SET
  last_name = left (trim(first_name), 1) || COALESCE(
    substring(
      trim(last_name)
      FROM
        2
    ),
    ''
  ),
  last_update = now ()
WHERE
  lower(left (trim(first_name), 1)) IN ('a', 'e', 'i', 'o', 'u')
  AND COALESCE(lower(left (trim(last_name), 1)), '') <> lower(left (trim(first_name), 1));
4. Find customers who made a purchase last year, categorize each by number of purchase and sort by purchases
WITH customer_counts AS (
  SELECT
    c.customer_id,
    c.first_name,
    c.last_name,
    c.email,
    COUNT(p.payment_id) AS purchases
  FROM payment p
  JOIN customer c USING (customer_id)
  WHERE p.payment_date >= date_trunc('year', current_date) - interval '1 year'
    AND p.payment_date <  date_trunc('year', current_date)
  GROUP BY c.customer_id, c.first_name, c.last_name, c.email
)
SELECT
  customer_id,
  first_name,
  last_name,
  email,
  purchases,
  CASE
    WHEN purchases = 1 THEN '1'
    WHEN purchases BETWEEN 2 AND 5 THEN '2-5'
    WHEN purchases BETWEEN 6 AND 10 THEN '6-10'
    ELSE '11+'
  END AS purchase_category
FROM customer_counts
ORDER BY purchases DESC;
5. Create customers table with id, first_name, last_name, email, image_url, created_at, updated_at
CREATE TABLE IF NOT EXISTS customers (
  id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  first_name varchar(100) NOT NULL,
  last_name varchar(100) NOT NULL,
  email varchar(320) NOT NULL UNIQUE,
  image_url text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

-- Trigger function to update updated_at on UPDATE
CREATE OR REPLACE FUNCTION public.set_updated_at()
RETURNS trigger AS $$
BEGIN
  NEW.updated_at := now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Create trigger (drop existing to ensure idempotence)
DROP TRIGGER IF EXISTS set_updated_at ON customers;
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON customers
FOR EACH ROW
EXECUTE FUNCTION public.set_updated_at();
6. Create customers table with id (uuid_generate_v4), first_name (nullable), last_name (nullable), email, image_url, created_at, updated_at
-- Ensure uuid_generate_v4() is available
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Create customers table with requested columns
CREATE TABLE IF NOT EXISTS customers (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
  first_name varchar,
  last_name varchar,
  email varchar NOT NULL,
  image_url text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

-- Enforce unique emails
CREATE UNIQUE INDEX IF NOT EXISTS customers_email_idx ON customers(email);

-- Trigger function to update updated_at on UPDATE
CREATE OR REPLACE FUNCTION customers_set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at := now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Create trigger (drop existing to ensure idempotence)
DROP TRIGGER IF EXISTS customers_set_updated_at_trg ON customers;
CREATE TRIGGER customers_set_updated_at_trg
BEFORE UPDATE ON customers
FOR EACH ROW
EXECUTE FUNCTION customers_set_updated_at();
7. Create view "Customers NYC" for all customers from New York City
CREATE OR REPLACE VIEW "Customers NYC" AS
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email,
  c.active,
  c.store_id,
  c.create_date,
  c.last_update,
  a.address     AS street,
  a.address2    AS street2,
  a.district,
  a.postal_code,
  a.phone,
  ci.city       AS city
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
WHERE ci.city ILIKE 'new york%';
8. Create view "Expensive Products" that get all products with higher than average price
CREATE OR REPLACE VIEW "Expensive Products" AS
SELECT
  film_id,
  title,
  rental_rate
FROM film
WHERE rental_rate > (
  SELECT AVG(rental_rate) FROM film
);
9. Create stored procedure for getting customers with city as parameter
CREATE OR REPLACE FUNCTION get_customers_by_city_partial(p_city TEXT)
RETURNS TABLE (
  customer_id smallint,
  first_name varchar,
  last_name varchar,
  email varchar,
  address varchar,
  city varchar,
  postal_code varchar,
  phone varchar
)
LANGUAGE sql
AS $$
  SELECT c.customer_id,
         c.first_name,
         c.last_name,
         c.email,
         a.address,
         ci.city,
         a.postal_code,
         a.phone
  FROM customer c
  JOIN address a ON c.address_id = a.address_id
  JOIN city ci ON a.city_id = ci.city_id
  WHERE ci.city ILIKE '%' || p_city || '%';
$$;
10. Create function for daily created customers
CREATE FUNCTION daily_created_customers(start_date date, end_date date)
RETURNS TABLE(created_day date, customer_count bigint)
LANGUAGE sql
AS $$
  SELECT gs.d::date AS created_day,
         COALESCE(cnt.customer_count, 0) AS customer_count
  FROM generate_series(start_date::date, end_date::date, interval '1 day') AS gs(d)
  LEFT JOIN (
    SELECT create_date::date AS day, COUNT(*)::bigint AS customer_count
    FROM customer
    WHERE create_date >= start_date::date
      AND create_date < (end_date::date + interval '1 day')
    GROUP BY create_date::date
  ) cnt ON cnt.day = gs.d::date
  ORDER BY created_day;
$$;

Try these on your own queries

Generate, optimize, validate, explain, and format SQL with the SQLAI.ai tools — across every supported database.