SELECT INTO — Copy into a New Table
Create and fill a brand-new table from a query in one step with SQL Server's SELECT … INTO.
Before a risky update, a careful developer makes a backup copy of the table. In SQL Server you can create that copy — structure and data — in a single statement: SELECT … INTO.
Definition
SELECT … INTO is a SQL Server (T-SQL) statement that creates a brand-new table and fills it with the rows returned by a SELECT query — in one step. The new table's columns and data types are taken from the query's result.
- Brand-new table — the target must not exist yet (otherwise: "There is already an object named … in the database").
- Columns from the query — names and data types come from the SELECT list (use aliases to name calculated columns).
- One step — no separate
CREATE TABLEneeded.
Syntax
sql
SELECT column1, column2, ...
INTO new_table
FROM source_table
WHERE condition;| Part | Meaning |
|---|---|
SELECT … | The columns to copy (* for all) |
INTO new_table | Name of the table to create — it goes right after the SELECT list |
FROM source_table | Where the rows come from |
WHERE … | (Optional) which rows to copy |
Example — back up the players table
sql
SELECT *
INTO players_backup
FROM players;SQL Server reports (6 rows affected) and players_backup now exists with the same 6 rows and the same column names and types.
Example — copy a filtered subset
sql
SELECT id, name, runs
INTO top_batters
FROM players
WHERE runs >= 700;
SELECT * FROM top_batters;| id | name | runs |
|---|---|---|
| 1 | Virat Kohli | 750 |
| 3 | Jos Buttler | 850 |
| 5 | David Warner | 700 |
What is NOT copied
SELECT INTO copies columns, data types, NULL-ability and data (and an IDENTITY property in simple cases). It does not copy:
- the PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY or DEFAULT constraints,
- indexes or triggers.
So a backup made with SELECT INTO is a plain table — add a primary key afterwards if you need one.
Tricks
sql
-- Copy only the STRUCTURE (an empty table): a WHERE that is never true
SELECT *
INTO players_empty
FROM players
WHERE 1 = 0;
-- Copy into a temporary table (#) that disappears when your session ends
SELECT *
INTO #indian_players
FROM players
WHERE country = 'India';SELECT INTO vs INSERT INTO … SELECT
SELECT … INTO new_table | INSERT INTO table … SELECT | |
|---|---|---|
| Target table | Must NOT exist — it is created | Must already exist |
| Defines columns | Automatically, from the query | You defined them in CREATE TABLE |
| Copies constraints? | No | Target keeps its own constraints |
| Can run twice? | No — second run fails (table exists) | Yes — adds the rows again |
| Portability | SQL Server only | Standard SQL, works everywhere |
SQL Server vs MySQL / PostgreSQL
| Database | Create a table from a query |
|---|---|
| SQL Server | SELECT * INTO players_backup FROM players; |
| MySQL | CREATE TABLE players_backup AS SELECT * FROM players; |
| PostgreSQL | CREATE TABLE players_backup AS SELECT * FROM players; (PostgreSQL also accepts SELECT INTO) |
Note (playground): The browser playground doesn't support
SELECT … INTO. The runnable example below shows the same idea withCREATE TABLE+INSERT INTO … SELECT, which also works in SQL Server.
Common mistakes
- ❌ Running
SELECT INTOwhen the target already exists → error. ✅ Use a new name,DROP TABLE IF EXISTSfirst, or useINSERT INTO … SELECT. - ❌ Expecting the primary key to be copied. ✅ Add it afterwards with
ALTER TABLE … ADD CONSTRAINT. - ❌ Putting
INTOin the wrong place (SELECT * FROM players INTO backup). ✅INTOcomes right after the column list, beforeFROM. - ❌ Unnamed calculated columns:
SELECT runs * 2 INTO …→ error. ✅ Give an alias:runs * 2 AS double_runs.
Interview tip
Q: What's the difference between SELECT INTO and INSERT INTO SELECT?
A: SELECT INTO creates a new table from the query result (it must not exist), copying columns and data but not constraints or indexes. INSERT INTO … SELECT adds rows to a table that already exists.
Key points to remember
- SELECT … INTO creates a NEW table and fills it with a query's rows in one step (SQL Server).
- INTO new_table goes right after the SELECT list and before FROM.
- The new table must not exist yet; its columns and types come from the query.
- Constraints (PK, FK, UNIQUE, CHECK, DEFAULT), indexes and triggers are NOT copied.
- WHERE 1 = 0 copies only the structure (an empty table).
- INSERT INTO … SELECT needs an existing table; SELECT INTO creates it.
- MySQL/PostgreSQL use CREATE TABLE new_table AS SELECT … instead.
Try it yourself
SQL Server: back up players with SELECT INTO
-- Full backup: structure + all 6 rows
SELECT *
INTO players_backup
FROM players;
-- Filtered copy
SELECT id, name, runs
INTO top_batters
FROM players
WHERE runs >= 700;
-- Structure only (0 rows)
SELECT *
INTO players_empty
FROM players
WHERE 1 = 0;SQL Server-specific — run this in SQL Server (SSMS / Azure Data Studio).
Try it: same idea in the playground
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Practice: back up just the MI players
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Revision Flashcards
Tap a card to flip it and see the answer.
