Share via

INSERT (Transact-SQL)

Adds one or more new rows to a table or a view. For examples, see INSERT Examples (Transact-SQL).

Topic link iconTransact-SQL Syntax Conventions


[ WITH <common_table_expression> [ ,...n ] ]
    [ TOP (expression) [ PERCENT ] ] 
    [ INTO ] 
    { <object> | rowset_function_limited 
      [ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
    [ (column_list) ] 
    [ <OUTPUT Clause> ]
    { VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n ] 
    | derived_table 
    | execute_statement
    | <dml_table_source>
[; ]

<object> ::=
    [ server_name . database_name . schema_name . 
      | database_name .[ schema_name ] . 
      | schema_name . 

<dml_table_source> ::=
    SELECT <select_list>
    FROM ( <dml_statement_with_output_clause> ) 
      [AS] table_alias [ ( column_alias [ ,...n ] ) ]
    [ WHERE <search_condition> ]
    [ OPTION ( <query_hint> [ ,...n ] ) ]


  • WITH <common_table_expression>
    Specifies the temporary named result set, also known as common table expression, defined within the scope of the INSERT statement. The result set is derived from a SELECT statement.

    Common table expressions can also be used with the SELECT, DELETE, UPDATE, and CREATE VIEW statements. For more information, see WITH common_table_expression (Transact-SQL).

  • TOP (expression) [ PERCENT ]
    Specifies the number or percent of random rows that will be inserted. expression can be either a number or a percent of the rows. The rows referenced in the TOP expression that are used with INSERT, UPDATE, or DELETE are not arranged in any order.

    Parentheses delimiting expression in TOP are required in INSERT, UPDATE, and DELETE statements. For more information, see TOP (Transact-SQL).

  • INTO
    Is an optional keyword that can be used between INSERT and the target table.

  • server_name
    Is the name of the linked server on which the table or view is located. server_name can be specified as a linked server name, or by using the OPENDATASOURCE function.

    When server_name is specified as a linked server, database_name and schema_name are required. When server_name is specified with OPENDATASOURCE, database_name and schema_name may not apply to all data sources and is subject to the capabilities of the OLE DB provider that accesses the remote object. For more information, see Distributed Queries.

  • database_name
    Is the name of the database.

  • schema_name
    Is the name of the schema to which the table or view belongs.

  • table_or view_name
    Is the name of the table or view that is to receive the data.

    A table variable, within its scope, can be used as a table source in an INSERT statement.

    The view referenced by table_or_view_name must be updatable and reference exactly one base table in the FROM clause of the view. For example, an INSERT into a multitable view must use a column_list that references only columns from one base table. For more information about updatable views, see CREATE VIEW (Transact-SQL).

  • rowset_function_limited
    Is either the OPENQUERY or OPENROWSET function. Use of these functions is subject to the capabilities of the OLE DB provider that accesses the remote object. For more information, see Distributed Queries.

  • WITH ( <table_hint_limited> [... n ] )
    Specifies one or more table hints that are allowed for a target table. The WITH keyword and the parentheses are required.

    READPAST, NOLOCK, and READUNCOMMITTED are not allowed. For more information about table hints, see Table Hints (Transact-SQL).


    The ability to specify the HOLDLOCK, SERIALIZABLE, READCOMMITTED, REPEATABLEREAD, or UPDLOCK hints on tables that are targets of INSERT statements will be removed in a future version of SQL Server. These hints do not affect the performance of INSERT statements. Avoid using them in new development work, and plan to modify applications that currently use them.

    Specifying the TABLOCK hint on a table that is the target of an INSERT statement has the same effect as specifying the TABLOCKX hint. An exclusive lock is taken on the table.

  • (column_list)
    Is a list of one or more columns in which to insert data. column_list must be enclosed in parentheses and delimited by commas.

    If a column is not in column_list, the Database Engine must be able to provide a value based on the definition of the column; otherwise, the row cannot be loaded. The Database Engine automatically provides a value for the column if the column:

    • Has an IDENTITY property. The next incremental identity value is used.

    • Has a default. The default value for the column is used.

    • Has a timestamp data type. The current timestamp value is used.

    • Is nullable. A null value is used.

    • Is a computed column. The calculated value is used.

    column_list and a values list must be used when explicit values are inserted into an identity column, and the SET IDENTITY_INSERT option must be ON for the table.

  • OUTPUT Clause
    Returns inserted rows as part of the insert operation. The results can be returned to the processing application or inserted into a table or table variable for further processing.

    The OUTPUT clause is not supported in DML statements that reference local partitioned views, distributed partitioned views, or remote tables, or INSERT statements that contain an execute_statement. The OUTPUT INTO clause is not supported in INSERT statements that contain a <dml_table_source> clause.

    Introduces the list or lists of data values to be inserted. There must be one data value for each column in column_list, if specified, or in the table. The value list must be enclosed in parentheses.

    If the values in the Value list are not in the same order as the columns in the table or do not have a value for each column in the table, column_list must be used to explicitly specify the column that stores each incoming value.

    SQL Server 2008 introduces the Transact-SQL row constructor (also called a table value constructor) to specify multiple rows in a single INSERT statement. The row constructor consists of a single VALUES clause with multiple value lists enclosed in parentheses and separated by a comma. For more information, see Table Value Constructor (Transact-SQL).

    Forces the Database Engine to load the default value defined for a column. If a default does not exist for the column and the column allows null values, NULL is inserted. For a column defined with the timestamp data type, the next timestamp value is inserted. DEFAULT is not valid for an identity column.

  • expression
    Is a constant, a variable, or an expression. The expression cannot contain an EXECUTE statement.

    When referencing the Unicode character data types nchar, nvarchar, and ntext, 'expression' should be prefixed with the capital letter 'N'. If 'N' is not specified, SQL Server converts the string to the code page that corresponds to the default collation of the database or column. Any characters not found in this code page are lost. For more information, see Server-Side Programming with Unicode.

  • derived_table
    Is any valid SELECT statement that returns rows of data to be loaded into the table. The SELECT statement cannot contain a common table expression (CTE).

  • execute_statement
    Is any valid EXECUTE statement that returns data with SELECT or READTEXT statements.

    If execute_statement is used with INSERT, each result set must be compatible with the columns in the table or in column_list.

    execute_statement can be used to execute stored procedures on the same server or a remote server. The procedure in the remote server is executed, and the result sets are returned to the local server and loaded into the table in the local server. In a distributed transaction, execute_statement cannot be issued against a loopback linked server when the connection has multiple active result sets (MARS) enabled.

    If execute_statement returns data with the READTEXT statement, each READTEXT statement can return a maximum of 1 MB (1024 KB) of data. execute_statement can also be used with extended procedures. execute_statement inserts the data returned by the main thread of the extended procedure; however, output from threads other than the main thread are not inserted.

    You cannot specify a table-valued parameter as the target of an INSERT EXEC statement; however, it can be specified as a source in the INSERT EXEC string or stored-procedure. For more information, see Table-Valued Parameters (Database Engine).

  • <dml_table_source>
    Specifies that the rows inserted into the target table are those returned by the OUTPUT clause of an INSERT, UPDATE, DELETE, or MERGE statement, optionally filtered by a WHERE clause. If <dml_table_source> is specified, the target of the outer INSERT statement must meet the following restrictions:

    • It must be a base table, not a view.

    • It cannot be a remote table.

    • It cannot have any triggers defined on it.

    • It cannot participate in any primary key-foreign key relationships.

    • It cannot participate in merge replication or updatable subscriptions for transactional replication.

    The compatibility level of the database must be set to 100.

  • <select_list>
    Is a comma-separated list specifying which columns returned by the OUTPUT clause to insert. The columns in <select_list> must be compatible with the columns into which values are being inserted. <select_list> cannot reference aggregate functions or TEXTPTR.


    Any variables listed in the SELECT list refer to their original values, regardless of any changes made to them in <dml_statement_with_output_clause>.

  • <dml_statement_with_output_clause>
    Is a valid INSERT, UPDATE, DELETE, or MERGE statement that returns affected rows in an OUTPUT clause. The statement cannot contain a WITH clause, and cannot target remote tables or partitioned views. If UPDATE or DELETE is specified, it cannot be a cursor-based UPDATE or DELETE. Source rows cannot be referenced as nested DML statements.

  • WHERE <search_condition>
    Is any WHERE clause containing a valid <search_condition> that filters the rows returned by <dml_statement_with_output_clause>. For more information, see Search Condition (Transact-SQL). When used in this context, <search_condition> cannot contain subqueries, scalar user-defined functions that perform data access, aggregate functions, TEXTPTR, or full-text search predicates.

    Forces the new row to contain the default values defined for each column.

Best Practices for Bulk Loading Data

Using INSERT INTO…SELECT to Bulk Load Data with Minimal Logging

You can use INSERT INTO <target_table> SELECT <columns> FROM <source_table> to efficiently transfer a large number of rows from one table, such as a staging table, to another table with minimal logging. Minimal logging can improve the performance of the statement and reduce the possibility of the operation filling the available transaction log space during the transaction.

Minimal logging for this statement has the following requirements:

  • The recovery model of the database is set to simple or bulk-logged.

  • The target table is an empty or nonempty heap.

  • The target table is not used in replication.

  • The TABLOCK hint is specified for the target table.

Rows that are inserted into a heap as the result of an insert action in a MERGE statement may also be minimally logged.

Unlike the BULK INSERT statement, which holds a less restrictive Bulk Update lock, INSERT INTO…SELECT with the TABLOCK hint holds an exclusive (X) lock on the table. This means that you cannot insert rows using parallel insert operations. For more information about locks, see Lock Modes.

Using OPENROWSET and BULK to Bulk Load Data

The OPENROWSET function can accept the following table hints, which provide bulk-load optimizations with the INSERT statement:

  • The TABLOCK hint can minimize the number of log records for the insert operation. The recovery model of the database must be set to simple or bulk-logged and the target table cannot be used in replication. For more information, see Prerequisites for Minimal Logging in Bulk Import.

  • The IGNORE_CONSTRAINTS hint can temporarily disable FOREIGN KEY and CHECK constraint checking.

  • The IGNORE_TRIGGERS hint can temporarily disable trigger execution.

  • The KEEPDEFAULTS hint allows the insertion of a table column's default value, if any, instead of NULL when the data record lacks a value for the column.

  • The KEEPIDENTITY hint allows the identity values in the imported data file to be used for the identity column in the target table.

These optimizations are similar to those available with the BULK INSERT command. For more information, see Table Hints (Transact-SQL).

Data Types

When you insert rows, consider the following data type behavior:

  • If a value is being loaded into columns with a char, varchar, or varbinary data type, the padding or truncation of trailing blanks (spaces for char and varchar, zeros for varbinary) is determined by the SET ANSI_PADDING setting defined for the column when the table was created. For more information, see SET ANSI_PADDING (Transact-SQL).

    The following table shows the default operation for SET ANSI_PADDING OFF.

    Data type

    Default operation


    Pad value with spaces to the defined width of column.


    Remove trailing spaces to the last non-space character or to a single-space character for strings made up of only spaces.


    Remove trailing zeros.

  • If an empty string (' ') is loaded into a column with a varchar or text data type, the default operation is to load a zero-length string.

  • Inserting a null value into a text or image column does not create a valid text pointer, nor does it preallocate an 8-KB text page. For more information about inserting text and image data, see Using text, ntext, and image Functions.

  • Columns created with the uniqueidentifier data type store specially formatted 16-byte binary values. Unlike with identity columns, the Database Engine does not automatically generate values for columns with the uniqueidentifier data type. During an insert operation, variables with a data type of uniqueidentifier and string constants in the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (36 characters including hyphens, where x is a hexadecimal digit in the range 0-9 or a-f) can be used for uniqueidentifier columns. For example, 6F9619FF-8B86-D011-B42D-00C04FC964FF is a valid value for a uniqueidentifier variable or column. Use the NEWID() function to obtain a globally unique ID (GUID).

Inserting Values into User-Defined Type Columns

You can insert values in user-defined type columns by:

  • Supplying a value of the user-defined type.

  • Supplying a value in a SQL Server system data type, as long as the user-defined type supports implicit or explicit conversion from that type. The following example shows how to insert a value in a column of user-defined type Point, by explicitly converting from a string.

    INSERT INTO Cities (Location)
    VALUES ( CONVERT(Point, '12.3:46.2') );

    A binary value can also be supplied without performing explicit conversion, because all user-defined types are implicitly convertible from binary. For more information about conversion and user-defined types, see Performing Operations on User-defined Types.

  • Calling a user-defined function that returns a value of the user-defined type. The following example uses a user-defined function CreateNewPoint() to create a new value of user-defined type Point and insert the value into the Cities table.

    INSERT INTO Cities (Location)
    VALUES ( dbo.CreateNewPoint(x, y) );

Error Handling

You can implement error handling for the INSERT statement by specifying the statement in a TRY…CATCH construct. For more information, see Using TRY...CATCH in Transact-SQL.

If an INSERT statement violates a constraint or rule, or if it has a value incompatible with the data type of the column, the statement fails and an error message is returned.

If INSERT is loading multiple rows with SELECT or EXECUTE, any violation of a rule or constraint that occurs from the values being loaded causes the statement to be stopped, and no rows are loaded.

When an INSERT statement encounters an arithmetic error (overflow, divide by zero, or a domain error) occurring during expression evaluation, the Database Engine handles these errors as if SET ARITHABORT is set to ON. The batch is stopped, and an error message is returned. During expression evaluation when SET ARITHABORT and SET ANSI_WARNINGS are OFF, if an INSERT, DELETE or UPDATE statement encounters an arithmetic error, overflow, divide-by-zero, or a domain error, SQL Server inserts or updates a NULL value. If the target column is not nullable, the insert or update action fails and the user receives an error. For more information, see Behavior When ARITHABORT and ARITHIGNORE Are Set to ON.


When an INSTEAD OF trigger is defined on INSERT actions against a table or view, the trigger executes instead of the INSERT statement. For more information about INSTEAD OF triggers, see CREATE TRIGGER (Transact-SQL).

Limitations and Restrictions

When you insert values into remote tables and not all values for all columns are specified, you must identify the columns to which the specified values are to be inserted.

The setting of the SET ROWCOUNT option is ignored for INSERT statements against local and remote partitioned views. Also, this option is not supported for INSERT statements issued against remote tables.


Using SET ROWCOUNT will not affect DELETE, INSERT, and UPDATE statements in the next release of SQL Server. Do not use SET ROWCOUNT with DELETE, INSERT, and UPDATE statements in new development work, and plan to modify applications that currently use it. We recommend that you use the TOP clause instead.

Logging Behavior

The INSERT statement is always fully logged except when using the OPENROWSET function with the BULK keyword or when using INSERT INTO <target_table> SELECT <columns> FROM <source_table>. These operations can be minimally logged. For more information, see the section "Best Practices for Bulk Loading Data" earlier in this topic.


During a linked server connection, the sending server provides a login name and password to connect to the receiving server on its behalf. For this connection to work, you must create a login mapping between the linked servers by using sp_addlinkedsrvlogin. For more information, see Security for Linked Servers.

When you use OPENROWSET(BULK…), it is important to understand how SQL Server handles impersonation. For more information, see "Security Considerations" in Importing Bulk Data by Using BULK INSERT or OPENROWSET(BULK...).


INSERT permission is required on the target table.

INSERT permissions default to members of the sysadmin fixed server role, the db_owner and db_datawriter fixed database roles, and the table owner. Members of the sysadmin, db_owner, and the db_securityadmin roles, and the table owner can transfer permissions to other users.

To execute INSERT with the OPENROWSET function BULK option, you must be a member of the sysadmin fixed server role or of the bulkadmin fixed server role.


For examples, see INSERT Examples (Transact-SQL).