Select Into

Learn how to use PostgreSQL SELECT INTO to create a new table and populate it from a query result set.

4 min read · Last updated: March 2026 · Back to overview

Quick Answer

SELECT column_list INTO [TEMP] new_table FROM source_table WHERE condition creates a new table and fills it with the query result. Use the TEMP keyword to create a temporary table that is dropped at the end of the session.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

SELECT INTO is a PostgreSQL extension to the standard SELECT statement that creates a new table and fills it with data from a query in a single step. Unlike a regular SELECT, it does not return rows to the client — instead it writes them directly into the new table. This is useful for creating working copies of data, archiving subsets of rows, or building staging tables for data processing pipelines.

SELECT INTO syntax

SELECT select_list
INTO [TEMPORARY | TEMP] [TABLE] new_table_name
FROM source_table
WHERE condition;
  • The new table inherits column names and data types from the SELECT clause output.
  • The TEMP or TEMPORARY keyword creates a temporary table that is automatically dropped at the end of the session.
  • The TABLE keyword is optional and only improves readability.
  • You can use JOIN, GROUP BY, HAVING, and other SELECT clauses.

Note: You cannot use SELECT INTO inside a PL/pgSQL function because PL/pgSQL interprets the INTO clause as an assignment to a variable. Use CREATE TABLE AS instead in that context.

SELECT INTO examples

Example 1 — create a permanent table from a filtered query:

SELECT film_id, title, rental_rate
INTO TABLE film_r
FROM film
WHERE rating = 'R'
  AND rental_duration = 5
ORDER BY title;

Query the new table to verify the data:

SELECT * FROM film_r LIMIT 5;

Example 2 — create a temporary table for short films:

SELECT film_id, title, length
INTO TEMP TABLE short_film
FROM film
WHERE length < 60
ORDER BY title;

Check the results:

SELECT * FROM short_film ORDER BY length DESC;

 film_id |        title         | length
---------+----------------------+--------
     486 | Jet Neighbors        |     59
     465 | Interview Liaisons   |     59
     409 | Heartbreakers Bright |     59
     947 | Vision Torque        |     59
...

SELECT INTO tips

  • Prefer CREATE TABLE AS over SELECT INTO for new code — it is SQL-standard, works inside PL/pgSQL, and supports IF NOT EXISTS and UNLOGGED options.
  • The new table created by SELECT INTO does not inherit indexes, constraints, or sequences from the source table — add them explicitly after creation.
  • Use TEMP TABLE for intermediate computations within a session to avoid polluting the schema with one-off tables.
  • Name the target table clearly to distinguish permanent archive tables from ad-hoc working copies.

Reference: PostgreSQL documentation — SELECT INTO.

Continue in Managing Tables: Create Table As.

Related in this section: PostgreSQL Data Types · Create Table · Create Table As

Frequently Asked Questions

What is the difference between SELECT INTO and CREATE TABLE AS?

Both create a new table from a query result, but CREATE TABLE AS is the SQL standard syntax and is preferred. CREATE TABLE AS works inside PL/pgSQL functions, supports IF NOT EXISTS, UNLOGGED, and lets you specify custom column names. SELECT INTO is a PostgreSQL extension and cannot be used in PL/pgSQL because INTO has a different meaning there.

Does SELECT INTO copy indexes and constraints from the source table?

No. SELECT INTO (and CREATE TABLE AS) only copies the column structure and data. Indexes, primary keys, foreign keys, and other constraints are not transferred to the new table. You must add them explicitly with ALTER TABLE or CREATE INDEX after the table is created.

How do I create a temporary table with SELECT INTO?

Add the TEMP or TEMPORARY keyword after INTO: SELECT col1, col2 INTO TEMP TABLE temp_table_name FROM source WHERE condition. The temporary table is automatically dropped when the session ends.

Can I use SELECT INTO with a JOIN?

Yes. Any valid SELECT clause works with SELECT INTO, including JOINs, GROUP BY, HAVING, ORDER BY, and LIMIT. For example: SELECT a.id, b.name INTO new_table FROM a JOIN b ON a.b_id = b.id.

What error occurs if the target table already exists?

PostgreSQL returns: ERROR: relation "table_name" already exists. Unlike CREATE TABLE AS, SELECT INTO does not support an IF NOT EXISTS option. Drop or rename the existing table first, or use CREATE TABLE IF NOT EXISTS ... AS query instead.