Skip to content
10 Actually Useful SQL Queries (2026)

10 Actually Useful SQL Queries (2026)

DodaTech Updated Jun 20, 2026 4 min read

You know SELECT, JOIN, and GROUP BY. So does everyone. This list covers the SQL patterns that separate production developers from beginners — the queries you write when you need answers that simple aggregations can’t provide. All examples use PostgreSQL syntax.

The Queries

Window Functions: ROW_NUMBER for Deduplication — Assign a unique rank to each row within a partition. Use it to delete duplicates while keeping one copy.

DELETE FROM orders WHERE id IN (
  SELECT id FROM (
    SELECT id, ROW_NUMBER() OVER (
      PARTITION BY customer_id, order_date ORDER BY created_at DESC
    ) AS rn FROM orders
  ) sub WHERE rn > 1
);

Output: Deletes all but the newest duplicate order per customer per day.

LAG and LEAD for Row Comparison — Access the previous or next row’s value without a self-join.

SELECT date, amount,
  LAG(amount, 1) OVER (ORDER BY date) AS prev_day,
  amount - LAG(amount, 1) OVER (ORDER BY date) AS change
FROM daily_sales ORDER BY date;

Output: Shows each day’s sales, the previous day’s sales, and the difference.

Recursive CTE for Tree Structures — Traverse hierarchical data (org charts, categories, comment threads) without application-level recursion.

WITH RECURSIVE org_tree AS (
  SELECT id, name, manager_id, 1 AS depth FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.name, e.manager_id, ot.depth + 1
  FROM employees e JOIN org_tree ot ON e.manager_id = ot.id
)
SELECT * FROM org_tree ORDER BY depth, name;

Output: Flattened org chart with depth column showing hierarchy level.

Running Total with SUM Window — Calculate cumulative sums without subqueries.

SELECT date, amount,
  SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions ORDER BY date;

Output: Each row shows the transaction and the running total up to that point.

Rolling Average (Moving Window) — Smooth noisy time-series data.

SELECT date, amount,
  AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS rolling_7day_avg
FROM daily_sales ORDER BY date;

Output: A 7-day rolling average that smooths daily fluctuations.

Date Bucketing with date_trunc — Group timestamps into consistent intervals.

SELECT date_trunc('week', created_at) AS week, COUNT(*) AS signups
FROM users GROUP BY week ORDER BY week;

Output: Weekly signup counts, with each row representing Monday of that week.

Pagination with the Seek Method — Cursor-based pagination that scales, unlike OFFSET.

SELECT id, name, created_at FROM users
WHERE created_at > '2026-06-01T00:00:00Z'
ORDER BY created_at ASC, id ASC
LIMIT 20;

Output: Next 20 users after the cursor. Works efficiently on millions of rows because it uses an index scan instead of counting skipped rows.

Find Duplicates Across Multiple Columns — Identify rows that share values in specific columns.

SELECT email, COUNT(*) FROM users
GROUP BY email HAVING COUNT(*) > 1;

Output: Lists every duplicate email and how many times it appears.

Upsert with ON CONFLICT — Insert or update in one atomic statement.

INSERT INTO inventory (sku, quantity, updated_at)
VALUES ('ABC-123', 50, NOW())
ON CONFLICT (sku) DO UPDATE SET
  quantity = inventory.quantity + EXCLUDED.quantity,
  updated_at = NOW();

Output: Inserts a new row or adds 50 to the existing quantity for that SKU.

Fuzzy Match with ILIKE and Similarity — Find approximate text matches.

SELECT name FROM products
WHERE name ILIKE '%wireless%mouse%' OR
  SIMILARITY(name, 'wireless mouse') > 0.3
ORDER BY SIMILARITY(name, 'wireless mouse') DESC
LIMIT 10;

Output: Products matching “wireless mouse” even with typos, abbreviations, or different word order. Requires pg_trgm extension.

Which query pattern saves the most performance?
Seek-method pagination. Replace OFFSET/LIMIT with WHERE cursor > last_seen_value and you eliminate full table scans on every page request. The difference grows with table size — OFFSET 100000 scans 100k rows, seek method scans just the page.
When should I use a recursive CTE vs application code?
Recursive CTEs are faster for small-to-medium hierarchies (thousands of nodes). For millions of nodes, consider a nested set model or materialized path. CTEs also hit the work_mem limit — set it higher for large traversals.
Do window functions work in MySQL and SQLite?
Yes — since MySQL 8.0 and SQLite 3.25. All major databases now support window functions. The syntax is standard SQL, so these queries are portable with minor dialect adjustments.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro