INSERT ... SELECT
Objectives
By the end of this lesson, you should be able to:
- Populate a table from the result of a
SELECT, instead of literal values - Explain when this is useful
💡 Why this matters: Sometimes the data you need to insert already exists, in another table, or as the result of some other query.
INSERT ... SELECTcopies it across directly, no need to read it out and type it back in as literal values.
⚠️ A note on verification: every statement and result in this lesson was run against a real, live PostgreSQL 18 database, using the
employeestable from Module 3, filtered withWHERE(covered fully in Module 6).
Copying Query Results Into a Table
CREATE TABLE engineering_employees (
id INTEGER PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
salary NUMERIC(10,2)
);
INSERT INTO engineering_employees (id, first_name, last_name, salary)
SELECT id, first_name, last_name, salary FROM employees WHERE department = 'Engineering';
id | first_name | last_name | salary
----+------------+-----------+---------
1 | Erin | Walsh | 78000.00
3 | Maya | Kapoor | 81000.00
Instead of VALUES (...), the INSERT is followed directly by a SELECT. Every row that SELECT returns becomes a row inserted into engineering_employees, matched up by position with the column list, exactly like a regular multi-row INSERT, except the values come from a live query instead of being typed out.
When This Is Useful
INSERT ... SELECT is common for tasks like archiving (copying old records into a _history table before deleting them), building a filtered or summarized copy of a table, or seeding a new table from an existing one, exactly like the engineering_employees example above. The source and destination don’t need identical columns, only the columns actually listed need to line up between the SELECT and the INSERT.
Try It
- Create a
high_earnerstable withid,first_name, andsalarycolumns. - Use
INSERT ... SELECTto populate it with every employee earning more than 70000 (WHERE salary > 70000). - Confirm the right rows landed in
high_earnersby selecting from it.
Recap
INSERT INTO table (columns...) SELECT ...inserts the result of a query, instead of literalVALUES.- Each returned row from the
SELECTbecomes one inserted row, matched by position to the column list. - Useful for archiving, copying filtered subsets of data, or seeding a new table from an existing one.
Next lesson: UPDATE, changing data that’s already in a table.