Relational databases: articles

Playgrounds / PostgreSQL

SQL sandbox

Try a query. Change it. See what the database does.

AI-generated

New to SQL? Start here

From product IDs to an order

Read a shop’s records, join a product name to a purchase and calculate its total.

4 guided steps · Editable SQL

Have a query in mind?

Explore a small shop database with five tables, or write SQL of your own.

Nothing to install. SQL runs in this browser tab. Leaving or restarting discards your practice data.

SQL sandbox

Find a lesson

Choose a question to explore. Starting a lesson creates a fresh database.

42 lessons

Facts and schema

  • Accept a valid quantity, reject an invalid one

    Change a practice order line and see what its quantity constraint permits.

    4 stepsArticle ↗
  • Keep the price a customer agreed to

    Change a catalogue price, compare two receipts, and decide which facts belong to a purchase.

    4 stepsArticle ↗
  • Delete a customer and prevent an old copy reviving them

    Follow dependent records, a deletion ledger and a retained snapshot through a model restore.

    5 stepsArticle ↗

Reading and changing data

  • From product IDs to an order

    Read the shop’s records, join two tables, and calculate what an order cost.

    4 stepsArticle ↗
  • Find why a join doubled the total

    Follow the rows through a join, repair an inflated aggregate, and retain an order with no lines.

    5 stepsArticle ↗
  • Continue a list while new orders arrive

    Compare an offset with a saved ordering key, then test what a changed ordering value can still break.

    4 stepsArticle ↗
  • Load an order list without multiplying its work

    Replace repeated child lookups, then see why combining two child collections can duplicate rows.

    5 stepsArticle ↗
  • A fast report can contain yesterday’s answer

    Build daily totals, store them in a materialized view, and follow a late correction through refresh.

    5 stepsArticle ↗

Concurrency and external work

  • Record a complete checkout

    Reserve two mugs, record their purchase and commit all three changes together.

    6 stepsArticle ↗
  • Recover from a rejected order line

    Let a checkout fail after its first changes, then end the failed transaction with rollback.

    7 stepsArticle ↗
  • Read your changes before deciding to commit

    See your own updates in a Repeatable Read transaction, roll them back, then commit a separate change.

    5 stepsArticle ↗
  • Recover a checkout without reserving twice

    Use a stable operation key, follow the returned-row branch, and reject a retry whose details changed.

    7 stepsArticle ↗
  • Search product words inside PostgreSQL

    Turn titles into searchable terms, match a query, and see how a committed title change changes the answer.

    4 stepsArticle ↗
  • Keep a search copy from bringing back an old product

    Observe a stale copy, apply a newer withdrawal and reject an older replay using per-product versions.

    5 stepsArticle ↗
  • Keep a committed change and its delivery obligation together

    Commit source state and an outbox event, model a lost delivery acknowledgement, and replay without undoing newer state.

    7 stepsArticle ↗

Work and storage

  • Follow rows through an execution plan

    Read filtering, grouping and sorting as connected operations, then compare estimates with execution.

    4 stepsArticle ↗
  • Count the pages an index saves

    Run the measurements from the Indexes article on its 60,000 orders, from a full table scan to a covering index, the cost of writes, an index the planner can only walk and a plan built on stale statistics.

    25 stepsArticle ↗
  • Follow the work behind a joined report

    Compare repeated index probes, a broad hash join and an ordered merge while checking the report’s actual totals.

    5 stepsArticle ↗
  • Find which partitions a query needs

    Create real PostgreSQL range partitions, inspect pruning, and test their boundaries and keys.

    6 stepsArticle ↗
  • Prune partitions after a parameter arrives

    Reuse a generic prepared plan, change its dates and see execution-time pruning choose a different child.

    5 stepsArticle ↗

Recovery and operation

  • A query changes as its data changes

    Compare estimated and actual rows, refresh statistics, and test a narrower access path.

    6 stepsArticle ↗
  • Change a column while old writers still exist

    Add a replacement column, synchronise old writes, backfill in batches and find the cutover boundary.

    7 stepsArticle ↗
  • Find what a recovered copy is missing

    Compare a model of an older restore with independently recorded successful requests.

    5 stepsArticle ↗
  • Read and update only what the job needs

    Use a nonowner role, column privileges and a row policy; inspect real denied statements.

    6 stepsArticle ↗
  • A copied change is not always a visible change

    Use an explicit SQL model to distinguish acknowledgement, a durable copy and an applied result.

    5 stepsArticle ↗

Distributed SQL

  • Move a tenant without losing its last change

    Model a live copy, detect a stale destination, apply changes and reject an old writer generation.

    7 stepsArticle ↗

PostgreSQL

  • Give a JSON field a dependable meaning

    Distinguish missing values from strings and numbers, then move a required capacity into a typed record.

    5 stepsArticle ↗
  • Follow an indexed read and a committed change

    Inspect PostgreSQL’s access path, update a stock row, and separate its identity from its row location.

    4 stepsArticle ↗
  • Match an index to what the query asks

    Compare ordered B-tree access, JSON containment with GIN and page-range elimination with BRIN.

    6 stepsArticle ↗
  • Watch an update change index-only access

    Compare row-version identity and heap fetches before an update, after it, and after vacuum.

    7 stepsArticle ↗
  • WAL can describe work that never commits

    Observe WAL generation for an update, roll it back, and compare the logical result with a committed update.

    5 stepsArticle ↗
  • Give the planner unequal tenants

    Compare custom and generic prepared plans, then remove the skew that made the parameter matter.

    6 stepsArticle ↗
  • Ask for five rows and inspect the work

    Compare a top-N sort with ordered access, then make that ordered scan reject early candidates.

    6 stepsArticle ↗
  • Derive candidates and weaken a summary

    Combine GIN posting sets, then compare BRIN on identical events placed in different physical orders.

    7 stepsArticle ↗
  • Derive which transactions a snapshot excludes

    Change a snapshot’s active list and boundary, then connect that membership decision to two stock versions.

    4 stepsArticle ↗
  • Keep a tenant in every relationship

    Expose a cross-tenant join, repair its equality and test a foreign key that rejects the wrong tenant.

    5 stepsArticle ↗
  • JSON predicates and their indexes

    Match an object, keep conditions on the same array member, and index the expression that the query actually searches.

    8 stepsArticle ↗
  • See how two row policies combine

    Add a policy that unexpectedly widens a worker’s view, then repair the combination and test it.

    6 stepsArticle ↗

PostgreSQL specialist capabilities

  • Words, positions and ranked search

    See what text search stores, distinguish a phrase from word membership, and keep search results inside application filters.

    8 stepsArticle ↗
  • Distance and the eligible neighbours

    Calculate exact distances for four synthetic points and see why filtering a small candidate list differs from finding neighbours inside the eligible set.

    4 stepsArticle ↗
  • Overlapping bookings and covered periods

    Use PostgreSQL ranges and GiST-backed constraints to reject overlapping ownership, then distinguish overlap from full-period coverage.

    9 stepsArticle ↗

Explore the foundations

  • Turn a product assumption into an acceptance case

    Inspect rounding, a rejected quantity and the surviving records before carrying the same business rules to another engine.

    4 stepsArticle ↗
About this playground

This is PostgreSQL running locally through PGlite, with one connection and disposable data. It supports SQL, not psql’s backslash commands. It does not reproduce separate concurrent connections, network failures or server performance.

Large results show at most 200 rows and 40 columns per statement, 2,000 characters per cell, 5,000 cells, 250,000 cell characters and 50 responses per run. The editor accepts up to 100,000 characters. The five most recent runs are kept. A run lasting 20 seconds automatically discards its session; you can stop it sooner.

Run PostgreSQL on your own computer →