Intermediate: combining and changing data · Changing data, transactions and ACID · topic 37 of 62 · 35 min
INSERT
Explanation
From reading to writing
So far every query only read data. Real apps also add, change and remove rows: a new customer signs up, an order is placed, a ticket is closed. The statements that change data are INSERT, UPDATE and DELETE, together called DML (data manipulation language). In the tasks of this module you write the change and then a SELECT to show the result.
INSERT one row
INSERT INTO customers (id, name, city, email, joined)
VALUES (7, 'Meena Joshi', 'Jaipur', 'meena@example.com', '2025-04-10');You may leave out the column list and give a value for every column in table order, but do not. If someone later adds a column or changes the order, an insert without names fails or, worse, puts values into the wrong columns without any error. Naming the columns makes the statement readable and safe.
Many rows at once
Most engines (SQLite, PostgreSQL, MySQL, SQL Server) accept several rows in one VALUES list, separated by commas. One statement with many rows is faster than many statements with one row each, because the database does the bookkeeping once.
INSERT INTO products (id, name, category, price, stock)
VALUES (9, 'Desi Ghee 1L', 'Grocery', 620, 20),
(10, 'Masala Box', 'Kitchen', 350, 18);Defaults, NULLs and generated ids
A column you leave out of the list gets its DEFAULT (set when the table was created) or, if it has none, NULL. If the column is NOT NULL with no default, the insert fails. In SQLite an INTEGER PRIMARY KEY you leave out is filled with the next number automatically; other engines use AUTO_INCREMENT (MySQL), IDENTITY (SQL Server) or GENERATED AS IDENTITY / SERIAL (PostgreSQL).
-- tickets: status DEFAULT 'Open', priority DEFAULT 'Normal', assigned_to has no default
INSERT INTO tickets (customer_id, subject) VALUES (4, 'Wrong size received');
-- new row: id 2 | 4 | Wrong size received | Open | Normal | NULLPostgreSQL, MySQL and SQL Server also accept the word DEFAULT inside VALUES to ask for the default explicitly. SQLite does not (it gives a syntax error), so there you simply leave the column out. INSERT INTO t DEFAULT VALUES inserts a row made only of defaults in SQLite and PostgreSQL.
INSERT ... SELECT: copying rows
Instead of VALUES you can write a SELECT. Every row it returns is inserted. This is how teams copy old rows into an archive table, fill a summary table, or move data between tables, without the data ever leaving the database.
INSERT INTO orders_archive (id, customer_id, order_date, status, archived_on)
SELECT id, customer_id, order_date, status, '2025-04-30'
FROM orders
WHERE status = 'Delivered';
-- 4 rows copied: 101, 102, 103, 106RETURNING: get the new rows back
After an insert, an app usually needs the generated id, for example to show "Ticket #3 created". RETURNING makes the INSERT itself return rows, like a SELECT. It works in SQLite 3.35 and later and in PostgreSQL. SQL Server writes OUTPUT INSERTED.id instead. MySQL has no RETURNING (apps call LAST_INSERT_ID()), while MariaDB supports it for INSERT and DELETE, so check your engine and version.
INSERT INTO tickets (customer_id, subject, priority)
VALUES (2, 'Refund not received', 'High')
RETURNING id, status, priority;
-- 3 | Open | HighCommon mistakes
- Inserting without a column list. Always name the columns.
- Values in the wrong order for the column list, such as a city in the email column. Read both lists side by side.
- Putting text without quotes, or numbers in quotes. Write 'Pune' and 620.
- Giving an id that already exists: "UNIQUE constraint failed: customers.id". Leave the id out and let the database generate it.
- Forgetting a NOT NULL column that has no default: "NOT NULL constraint failed". Supply a value or add a default.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
INSERT · 1/7
Until now we only read data. This module changes it, starting with INSERT, which adds rows.
Prefer a video by a teacher? Find free videos on “sql insert into values insert select returning tutorial” on YouTube ↗
In real life: Placing an order on a shopping site
When you press "Place order", the server inserts one row into an orders table and one row per cart item into order_items. It needs the new order id to link the items, so in PostgreSQL it typically writes INSERT ... RETURNING id, and in MySQL it reads LAST_INSERT_ID(). Old delivered orders are later copied to an archive table with INSERT ... SELECT, so the live table stays small.
INSERT INTO orders (customer_id, order_date, status)
VALUES (5, '2025-04-12', 'Placed')
RETURNING id;
-- 109Practice (0/4 done)
Add a new customer: id 7, name 'Meena Joshi', city 'Jaipur', email 'meena@example.com', joined '2025-04-10'. Name the columns in the INSERT. Then return id, name and city of all customers.
Add two products in ONE insert: (id 9, 'Desi Ghee 1L', 'Grocery', price 620, stock 20) and (id 10, 'Masala Box', 'Kitchen', price 350, stock 18). Then return id, name and price of all Grocery and Kitchen products, sorted by id.
An empty table orders_archive (id, customer_id, order_date, status, archived_on) exists. Copy every Delivered order into it with INSERT ... SELECT, setting archived_on to '2025-04-30'. Then return id, customer_id, order_date and archived_on from orders_archive.
tickets has defaults: status 'Open' and priority 'Normal'. Insert a ticket for customer_id 2 with subject 'Refund not received' and priority 'High', giving only those three columns, and make the INSERT itself return id, subject, status, priority and assigned_to with RETURNING.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- UPDATE and DELETE safelyChanging data, transactions and ACID · same module
- Upserts: insert or updateChanging data, transactions and ACID · same module
- Transactions: all or nothingChanging data, transactions and ACID · same module
- INSERT, UPDATE and DELETEBackend Development · Databases and SQL basics
- What is a database?Backend Development · Databases and SQL basics
- SELECT and WHERE: finding rowsBackend Development · Databases and SQL basics
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Why should an INSERT always name its columns?
Answer: It keeps working correctly if columns are added or reordered later
Without a column list, values are matched to columns by position, which breaks when the table changes.
A column is left out of an INSERT and has no DEFAULT and no NOT NULL. What value does it get?
Answer: NULL
With no default, a missing column becomes NULL.
What does INSERT INTO a (x, y) SELECT p, q FROM b WHERE ... do?
Answer: Inserts every row the SELECT returns, p into x and q into y
INSERT ... SELECT inserts one row per selected row, matching columns by position.
Which engine has no RETURNING clause, so apps read the new id with LAST_INSERT_ID()?
Answer: MySQL
MySQL has no RETURNING. SQL Server uses OUTPUT; MariaDB, SQLite and PostgreSQL support RETURNING.
In SQLite, you write INSERT INTO tickets (customer_id, subject, status) VALUES (3, 'Hi', DEFAULT). What happens?
Answer: A syntax error: SQLite does not accept DEFAULT in VALUES
Leave the column out instead. PostgreSQL, MySQL and SQL Server do accept DEFAULT there.
What does RETURNING id do at the end of an INSERT?Related
Answer: Gives back the id of the new row
RETURNING sends back values from the changed rows, such as the new id.
Why is "SELECT to check, then INSERT if missing" in app code risky?Related
Answer: Two requests can both see "missing" and both try to insert
That gap between check and write is a race condition. An upsert is one atomic statement.
In a students table, what is one row?Related
Answer: One student with all their details
A row is one item. A column is one detail that every row has.
From What is a database?
What does SELECT name FROM students WHERE marks > 80 return?Related
Answer: Names of students with marks above 80
SELECT name picks one column; WHERE marks > 80 keeps only the rows with more than 80.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Changing data, transactions and ACID” before its exam: UPDATE and DELETE safely, Upserts: insert or update, Transactions: all or nothing, ACID, isolation and locking.
- Module 8 exam: Changing data, transactions and ACID · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Schema design and normalisation. 62 topics left in the course before the final exam.