What SQL is used for
SQL (Structured Query Language) is the standard language for defining, querying and changing data in relational databases. You use it to create tables, insert and update rows, join related tables and summarise results with functions like SUM and COUNT. PostgreSQL, MySQL, MariaDB, SQLite, SQL Server and Oracle all speak SQL, each with its own dialect on top of the ISO standard.
This editor is for writing and tidying those statements in the browser. It highlights keywords, strings, numbers and comments, suggests SQL keywords as you type, matches brackets, and has find and replace, word wrap, a dark theme, fullscreen, copy, and a download that saves query.sql.
It does not connect to a database. Nothing you write is executed, so you won't see rows or errors here. Treat it as a scratchpad for migrations, reports and queries you'll paste into a real client.
Example: a running total with a window function
This script creates two tables, adds a few rows and then lists each customer's orders with a running total. It runs unchanged on PostgreSQL, MySQL 8, and SQLite 3.25 or later:
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
ordered_on DATE NOT NULL,
total DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers (id)
);
INSERT INTO customers (id, name) VALUES (1, 'Ada'), (2, 'Grace');
INSERT INTO orders (id, customer_id, ordered_on, total) VALUES
(1, 1, '2026-01-14', 120.00),
(2, 1, '2026-02-03', 80.50),
(3, 2, '2026-01-20', 45.00),
(4, 1, '2026-02-21', 99.50);
-- Running total of spend per customer, oldest order first
SELECT c.name,
o.ordered_on,
o.total,
SUM(o.total) OVER (
PARTITION BY o.customer_id
ORDER BY o.ordered_on
) AS running_total
FROM orders AS o
JOIN customers AS c ON c.id = o.customer_id
ORDER BY c.name, o.ordered_on;
Ada's running total goes 120.00, 200.50, 300.00, and Grace's single order gives 45.00. SQLite prints 120 rather than 120.00: a DECIMAL column gets NUMERIC affinity there, which stores 120.00 as the integer 120 and 80.50 as a floating-point number. The foreign key is declared as a separate table constraint because MySQL has historically ignored the inline REFERENCES form on a column.
Dialect differences that bite
Most of the language is portable. These four things are not, and each has caught people copying a query between databases:
| Topic | Standard / PostgreSQL | MySQL | SQL Server |
|---|---|---|---|
| Quoting a name | "order" |
`order` (double quotes are strings unless ANSI_QUOTES is on) |
[order] or "order" |
| Joining strings | 'a' || 'b' |
CONCAT('a', 'b'); || means logical OR by default |
'a' + 'b' or CONCAT |
| First n rows | FETCH FIRST 10 ROWS ONLY (PostgreSQL also takes LIMIT 10) |
LIMIT 10 |
TOP (10), or OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY after an ORDER BY |
| Line comments | -- note |
-- note needs a space after the dashes; # note also works |
-- note |
Sources: the PostgreSQL SELECT reference, MySQL's comment syntax and SQL modes pages, and Microsoft's T-SQL TOP documentation.
One rule holds everywhere: WHERE email = NULL never matches anything, because comparing with NULL yields unknown rather than true. Use IS NULL or IS NOT NULL, as the PostgreSQL comparison docs explain.
Running the script
- Click Download to save
query.sql. - Run it with the client for your database:
- SQLite:
sqlite3 shop.db < query.sql - PostgreSQL:
psql -d shop -f query.sql - MySQL or MariaDB:
mysql -u root -p shop < query.sql
- SQLite:
- Test against a throwaway database first when the script drops or updates data.
Keep learning SQL
The free SQL course starts from your first SELECT and has a full lesson on SQL dialects. Keep the SQL cheat sheet open for syntax, and paste a messy query into the SQL formatter to clean up its layout.
Last updated