Skip Navigation Links
Home
Articles
SQL Server 2012
SQL Server 2014
SQL Server 2016
FAQ
Practice Test
Tip of the Day : SQL Server Numeric Data Types
Home > SQL Server 2008 > Multiple Value Inserts Using a Single INSERT Statement
Multiple Value Inserts Using a Single INSERT Statement

One of the new programmability enhancements in the Database Engine introduced in SQL Server 2008 for Transact-SQL is the row constructor which consists of a single VALUES clause with multiple value lists enclosed in parentheses and separated by a comma.  With the row constructor, you can now insert multiple values using a single INSERT statement.

In SQL Server 2000 or SQL Server 2005, to insert multiple rows to a table, you would issue one INSERT statement for each record.  To illustrate, to insert the different States of the US in the [dbo].[USState] you would do something like the following:

CREATE TABLE [dbo].[USState] (
    [StateCode]    CHAR(2),
    [StateName]    VARCHAR(20)
)
GO

INSERT INTO [dbo].[USState] 
VALUES ('AK', 'Alaska')

INSERT INTO [dbo].[USState] 
VALUES ('AL', 'Alabama')

INSERT INTO [dbo].[USState] 
VALUES ('AR', 'Arkansas')

INSERT INTO [dbo].[USState] 
VALUES ('AZ', 'Arizona')

INSERT INTO [dbo].[USState] 
VALUES ('CA', 'California')
GO

SELECT * FROM [dbo].[USState]
GO

StateCode   StateName
---------   ------------
AK          Alaska
AL          Alabama
AR          Arkansas
AZ          Arizona
CA          California

The individual INSERT INTO... VALUES statement can now be simplified with the row constructor.  The script above will now look as follows:

CREATE TABLE [dbo].[USState] (
    [StateCode]    CHAR(2),
    [StateName]    VARCHAR(20)
)
GO

INSERT INTO [dbo].[USState]
VALUES ('AK', 'Alaska'),
       ('AL', 'Alabama'),
       ('AR', 'Arkansas'),
       ('AZ', 'Arizona'),
       ('CA', 'California')
GO

SELECT * FROM [dbo].[USState]
GO

StateCode   StateName
---------   ------------
AK          Alaska
AL          Alabama
AR          Arkansas
AZ          Arizona
CA          California

Combining SELECT and VALUES Clauses in the INSERT Statement Row Constructor

With the new row constructor which uses the VALUES clause of the INSERT statement, will it allow inserting values into a table records from another table?  In other words, will it allow a combination of specifying a list of values using the VALUES clause and getting data from another table using the SELECT statement.

To find out, let's say you have a table of super heroes called [dbo].[SuperHero] and you want to populate it with a few records using the INSERT INTO ... VALUES statement.  Aside from the list of values, you also have a table of X-Men super heroes that you want to insert into the master super heroes table.  Here's a script that illustrates the scenario:

CREATE TABLE [dbo].[SuperHero] ( 
    [SuperHeroName]     VARCHAR(50),
    [RealIdentity]      VARCHAR(50)
)
GO

CREATE TABLE [dbo].[X-Men] (
    [CodeName]          VARCHAR(50),
    [RealIdentity]      VARCHAR(50),
    [GoodGuy]           BIT
)
GO

INSERT INTO [dbo].[X-Men]
VALUES ('Wolverine', 'Logan', 1),
       ('Cyclops', 'Scott Summers', 1)
GO

INSERT INTO [dbo].[SuperHero]
VALUES ('Superman', 'Clark Kent'),
       ('Batman', 'Bruce Wayne'),
       ('Spiderman', 'Peter Parker'),
       (SELECT [CodeName], [RealIdentity] FROM [dbo].[X-Men] WHERE [GoodGuy] = 1)
GO

Unfortunately, executing this script will generate the following error:

Msg 156, Level 15, State 1, Line 6
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 6
Incorrect syntax near ')'.

This is an expected error because the row construcor only allows single scalar values inside the VALUES list for each column.  Subqueries are allowed as long as only a single column and a single row is returned by the subquery.  To overcome the error above, the query can be re-written as follows:

INSERT INTO [dbo].[SuperHero]
VALUES ('Superman', 'Clark Kent'),
       ('Batman', 'Bruce Wayne'),
       ('Spiderman', 'Peter Parker'),
      ((SELECT [CodeName] FROM [dbo].[X-Men] WHERE [CodeName] = 'Wolverine'),
       (SELECT [RealIdentity] FROM [dbo].[X-Men] WHERE [CodeName] = 'Wolverine'))
GO

As mentioned earlier, subqueries are allowed as long as the subquery returns only a single column and a single row.  If the subquery returns a single column but more than a single row, you will get the following error message:

INSERT INTO [dbo].[SuperHero]
VALUES ('Superman', 'Clark Kent'),
       ('Batman', 'Bruce Wayne'),
       ('Spiderman', 'Peter Parker'),
      ((SELECT [CodeName] FROM [dbo].[X-Men] WHERE [GoodGuy] = 1),
       (SELECT [RealIdentity] FROM [dbo].[X-Men] WHERE [GoodGuy] = 1))
GO
       

Msg 512, Level 16, State 1, Line 2
Subquery returned more than 1 value. 
This is not permitted when the subquery follows =, !=, <, <= , >, >= or 
when the subquery is used as an expression.
The statement has been terminated.

As can be seen from the script, only one record from the [dbo].[X-Men] can be retrieved and inserted at a time.  If you will be inserting multiple rows from one table to another, if you use the row constructor it's going to be a long script.  In this case, it is suggested that you separate the VALUES list from the subquery and issue 2 separate INSERT commands, as follows:

INSERT INTO [dbo].[SuperHero]
VALUES ('Superman', 'Clark Kent'),
       ('Batman', 'Bruce Wayne'),
       ('Spiderman', 'Peter Parker')
GO

INSERT INTO [dbo].[SuperHero]
SELECT [CodeName], [RealIdentity]
FROM [dbo].[X-Men]
WHERE [GoodGuy] = 1
GO

One limitation of the row constructor is the maximum number of rows that can be inserted, which is 1000 rows.  If you try to use the row constructor with more than 1000 rows, you will get the following error message:

Msg 10738, Level 15, State 1, Line 1002
The number of row value expressions in the INSERT statement
exceeds the maximum allowed number of 1000 row values.

To overcome this limitation, simply break the INSERT statement into multiple INSERT statements with each INSERT statement containing only 1000 rows to insert.

Related Articles :