What is INSERT?
INSERT is the SQL statement you use to add new rows to a table.
While SELECT reads data, INSERT writes it — permanently and immediately.
Basic syntax
INSERT INTO table_name (column1, column2, column3)
VALUES ('value1', 'value2', 'value3');
The column list and the value list must match in order and count. If you list three columns, you must provide exactly three values.
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Ana', 'Torres', 'ana@example.com', 'Lima');
Inserting multiple rows
You can insert several rows in a single statement by separating tuples with commas:
INSERT INTO departments (name, location)
VALUES
('Marketing', 'Lima'),
('Legal', 'Santiago');
One statement, two rows — more efficient than two separate INSERT calls.
Letting the database fill columns
Not every column needs a value from you.
In this dataset, id is GENERATED BY DEFAULT AS IDENTITY — the database assigns
the next integer automatically.
created_at on the customers table has DEFAULT now() — the database sets it to
the current timestamp if you omit it.
Omit those columns entirely from your INSERT:
-- id and created_at are filled by the database
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Pedro', 'Vega', 'pedro@example.com', 'Bogota');
If you supply an explicit id, PostgreSQL does not advance the identity
sequence — a later auto-generated id can collide with the one you forced. Omitting
id and letting the database assign it is the normal, safe pattern.
Returning what you inserted
PostgreSQL lets you read back the newly inserted row in the same statement:
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Laura', 'Nunez', 'laura@example.com', 'Santiago')
RETURNING *;
RETURNING is useful when you need the generated id or the server-generated
created_at right away — without a separate SELECT.
Try it
Run this against the classic company dataset:
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Test', 'User', 'test.user@example.com', 'Buenos Aires')
RETURNING id, first_name, email, created_at;
Notice that id and created_at appear in the result even though you did not
supply them.
Real-world note
UNIQUE constraints protect data integrity.
The email column on customers is declared UNIQUE, so inserting a duplicate
email raises an error:
ERROR: duplicate key value violates unique constraint "customers_email_key"
Always insert only the columns you own — never forge values the database is designed
to generate (identities, audit timestamps, UUIDs).
If you need to handle conflicts gracefully, PostgreSQL’s INSERT ... ON CONFLICT
clause is the right tool (beyond this lesson’s scope).
Summary
INSERT INTO table (cols) VALUES (vals)adds one row.- Column list and value list must match in order and count.
- Separate tuples with commas to insert multiple rows in one statement.
- Omit
id(identity) andDEFAULTcolumns — the database fills them. RETURNINGgives you the inserted row back, including generated values.UNIQUEconstraints reject duplicate values — protect your data model.