使用 INSERT 和 VALUES 插入行
INSERT 語句可向表中添加一個或多個新行。在簡化處理中,INSERT 具有以下格式:
INSERT [INTO] table_or_view [(column_list)] VALUES(data_values)
- column_list 是列名的列表,列名以逗號分隔,用于指定為其提供數據的列。如果未指定 column_list,表或視圖中的所有列都將接收到數據。當 column_list 未指定表或視圖中的所有列時,系統會將默認值(如果為列定義了默認值)或 NULL 插入未在列表中指定的任一列。未在列列表中指定的所有列必須允許空值或分配了默認值。
- VALUES 關鍵字為表的某一行或多個行指定值。這些值指定為逗號分隔的標量表達式列表,表達式的數據類型、精度和小數位數必須與列的列表中對應列一致,或者可以隱式轉換為列的列表中對應列。
INSERT 語句不指定下列類型列的值,因為 SQL Server 數據庫引擎將為這些列生成值:
- 具有 timestamp 數據類型。使用當前的時間戳值。
- 具有默認值的列,此默認值用 NEWID 函數生成唯一的 GUID 值。
- 可以為 Null。使用 Null 值。
- 標識列。標識列具有 IDENTITY 屬性的列,此屬性為該列生成值。
- 計算列。計算列是指定義為通過 CREATE TABLE 語句中一個或多個其他列計算的表達式的虛擬列,例如:
CREATE TABLE TestTable
(ColA INT PRIMARY KEY,
ColB INT NOT NULL,
ColC AS (ColA + ColB) * 2);
鎖定行為
??INSERT 語句總是在其修改的表上獲取排他 (X) 鎖并在事務完成之前持有該鎖。使用排他鎖(X 鎖)時,任何其他事務都無法修改數據;僅在使用 NOLOCK 提示或未提交讀隔離級別時才會進行讀取操作。
日志記錄行為
??INSERT 語句始終完全記入日志,只有在將 OPENROWSET 函數與 BULK 關鍵字一起使用或者在使用 INSERT INTO <target_table> SELECT <columns> FROM <source_table> 時除外。這些操作可進行最小日志記錄。
【示例】
??以下示例顯示了如何將行插入包含自動生成值或具有默認值的列的表中。INSERT 語句插入一些行,這些行只有部分列包含值。在最后一個 INSERT 語句中,未指定列并只插入了默認值。
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ('dbo.T1', 'U') IS NOT NULL
DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1
(
column_1 AS 'Computed column ' + column_2,
column_2 varchar(30)
CONSTRAINT default_name DEFAULT ('my column default'),
column_3 rowversion,
column_4 varchar(40) NULL
);
GO
INSERT INTO dbo.T1 (column_4)
VALUES ('Explicit value');
INSERT INTO dbo.T1 (column_2, column_4)
VALUES ('Explicit value', 'Explicit value');
INSERT INTO dbo.T1 (column_2)
VALUES ('Explicit value');
INSERT INTO T1 DEFAULT VALUES;
GO
SELECT column_1, column_2, column_3, column_4
FROM dbo.T1;
GO
查詢結果如下:
column_1 column_2 column_3 column_4
---------------------------------------------- ------------------------------ ---------- --------------------
Computed column my column default my column default 0x00000000 Explicit value
Computed column Explicit value Explicit value 0x00000000 Explicit value
Computed column Explicit value Explicit value 0x00000000 NULL
Computed column my column default my column default 0x00000000 NULL
使用 INSERT 和 SELECT 子查詢插入行
INSERT 語句中的 SELECT 子查詢可用于將一個或多個表或視圖中的值添加到另一個表中。使用 SELECT 子查詢還可以同時插入多行。
??子查詢的選擇列表必須與 INSERT 語句的列列表匹配。如果沒有指定列列表,選擇列表必須與正在其中執行插入操作的表或視圖的列匹配。
??在以下示例中,INSERT 語句將Sales.SalesReason 表中 SalesReason 為 Marketing 的所有行中的一些數據插入到一個單獨的表中:
USE AdventureWorks2008R2;
GO
CREATE TABLE MySalesReason (
SalesReasonID int NOT NULL,
Name nvarchar(50),
ModifiedDate datetime);
GO
INSERT INTO MySalesReason
SELECT SalesReasonID, Name, ModifiedDate
FROM AdventureWorks2008R2.Sales.SalesReason
WHERE ReasonType = N'Marketing';
GO
使用 SELECT INTO 插入行
SELECT INTO 語句用于創建一個新表,并用 SELECT 語句的結果集填充該表。SELECT INTO 可將幾個表或視圖中的數據組合成一個表。也可用于創建一個包含選自鏈接服務器的數據的新表。
??新表的結構由選擇列表中表達式的屬性定義。下面的示例中,從多個雇員和與地址相關的表中選擇七列來創建表 dbo.EmployeeAddresses。
USE AdventureWorks2008R2;
GO
SELECT c.FirstName, c.LastName, e.JobTitle, a.AddressLine1, a.City,
sp.Name AS [State/Province], a.PostalCode
INTO dbo.EmployeeAddresses
FROM Person.Person AS c
JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
JOIN Person.BusinessEntityAddress AS bea
ON e.BusinessEntityID = bea.BusinessEntityID
JOIN Person.Address AS a
ON bea.AddressID = a.AddressID
JOIN Person.StateProvince as sp
ON sp.StateProvinceID = a.StateProvinceID;
GO
SELECT INTO 不使用源表的分區方案。而新表是在默認文件組中創建的,若要向已分區表插入行,首先必須創建已分區表,然后再使用 INSERT INTO…SELECT FROM 語句。
??使用 SELECT INTO 語句創建新表時,FILESTREAM 屬性不傳輸。FILESTREAM BLOB 作為 varbinary(max) BLOB 復制并存儲在新表中。如果 FILESTREAM BLOB 超過 2 GB,則將引發以下錯誤消息,并且語句停止:“正嘗試增長 LOB,使其超過允許的最大大小(2147483647 個字節)”。
使用INSERT EXEC語句插入行
INSERT [INTO] table_name|table_variable [(column_list )] execute_statement
- table_name:表名,可以是永久表或臨時表
- table_variable:表變量(SQL Server不可用)
- execute_statement:任何有效的 EXECUTE 語句,它使用 SELECT 或 READTEXT 語句返回數據。
- 如果 execute_statement 使用 INSERT,則每個結果集必須與表或 column_list 中的列兼容。
- 如果 execute_statement 使用 READTEXT 語句返回數據,則每個 READTEXT 語句最多可以返回 1 MB (1024 KB) 的數據。
- execute_statement 還可以用于擴展過程。execute_statement 插入由擴展過程的主線程返回的數據,但不插入主線程以外的線程的輸出。
- 不能將表值參數指定為 INSERT EXEC 語句的目標;但是,可以將它指定為 INSERT EXEC 字符串或存儲過程中的源。
- 不能在 INSERT...EXEC 語句中使用 OUTPUT 子句
使用 TOP 限制插入的行
可以使用 TOP 關鍵字限制插入的行數。在與 INSERT語句結合使用的 TOP 表達式中引用的行不按任何順序排列。TOP(n) 隨機返回 n 行。
??例如,下面的 INSERT 語句包含 ORDER BY 子句,但該子句并不影響由 INSERT 語句直接引用的行,INSERT 語句選擇 SELECT 語句返回的任意兩行
INSERT TOP (2) INTO Table2 (ColumnB)
SELECT ColumnA FROM Table1
ORDER BY ColumnA;
若要確保插入 SELECT 子查詢返回的前兩行,請按如下所示重寫該查詢。
INSERT INTO Table2 (ColumnB)
SELECT TOP (2) ColumnA FROM Table1
ORDER BY ColumnA;
INSERT (Transact-SQL)
-- Standard INSERT syntax
[ WITH <common_table_expression> [ ,...n ] ]
INSERT
{
[ 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>
| DEFAULT VALUES
}
}
}
[; ]
<object> ::=
{
[ server_name . database_name . schema_name .
| database_name .[ schema_name ] .
| schema_name .
]
table_or_view_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 ] ) ]
- TOP (expression) [ PERCENT ]
指定將插入的隨機行的數目或百分比。expression 可以是行數或行的百分比。 - INTO:一個可選的關鍵字,可以將它用在 INSERT 和目標表之間。
- server_name:表或視圖所在的鏈接服務器的名稱。
- database_name:數據庫的名稱。
- schema_name:該表或視圖所屬架構的名稱。
- table_or view_name:要接收數據的表或視圖的名稱。表變量在其作用域內可用作 INSERT 語句中的表源。
- OUTPUT 子句:將插入行作為插入操作的一部分返回。結果可返回到處理應用程序或插入到表或表變量中以供進一步處理。
??引用本地分區視圖、分布式分區視圖或遠程表的 DML 語句或包含 execute_statement 的 INSERT 語句都不支持OUTPUT 子句。在包含 <dml_table_source> 子句的 INSERT 語句中不支持 OUTPUT INTO 子句。 - VALUES
引入要插入的數據值的一個或多個列表。對于 column_list(如果已指定)或表中的每個列,都必須有一個數據值。必須用圓括號將值列表括起來。 - DEFAULT
強制數據庫引擎加載為列定義的默認值。如果某列并不存在默認值,并且該列允許 Null 值,則插入 NULL。對于使用 timestamp 數據類型定義的列,插入下一個時間戳值。DEFAULT 對標識列無效。 - expression:一個常量、變量或表達式。表達式不能包含 EXECUTE 語句。
- <dml_table_source>
??指定插入目標表的行是 INSERT、UPDATE、DELETE 或 MERGE 語句的OUTPUT 子句返回的行(和上面的<OUTPUT Clause>沒啥關系,這里是使用DML產生所要插入目標表的行,它們是使用OUTPUT返回的)。
??如果指定了 <dml_table_source>,外部 INSERT 語句的目標必須滿足以下限制: - 必須是基表而不是視圖。
- 不能是遠程表。
- 不能對其定義任何觸發器。
- 不能參與任何主鍵-外鍵關系。
- 不能參與合并復制或事務復制的可更新訂閱。
- <select_list>
指定要插入 OUTPUT 子句所返回的列的逗號分隔列表。<select_list> 中的列必須與要插入值的列兼容。<select_list> 無法引用聚合函數或 TEXTPTR。 - <dml_statement_with_output_clause>
??在 OUTPUT 子句中返回受影響行的有效 INSERT、UPDATE、DELETE 或 MERGE 語句(和上面的<OUTPUT Clause>沒啥關系,這是產生data_table_source的DML語句)。
??語句中不能包含 WITH 子句,且不能以遠程表或分區視圖為目標。如果指定了 UPDATE 或 DELETE,則所指定的 UPDATE 或 DELETE 不能是基于游標的。源行不能作為嵌套的 DML 語句進行引用。 - WHERE <search_condition>
任意 WHERE 子句,其中包含對 <dml_statement_with_output_clause> 返回的行進行篩選的有效 <search_condition>
【示例】
A. 將 OUTPUT INTO 用于簡單 INSERT 語句
??下例向 ScrapReason
表插入一行,并使用 OUTPUT 子句將語句的結果返回給@MyTableVartable
變量。由于 ScrapReasonID
列使用 IDENTITY 屬性定義,因此未在 INSERT 語句中為該列指定一個值。但請注意,將在列inserted.ScrapReasonID
內的 OUTPUT 子句中返回由數據庫引擎為該列生成的值。
USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO @MyTableVar
VALUES (N'Operator error', GETDATE());
--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate FROM Production.ScrapReason;
GO
**B、使用<dml_table_source>進行插入 **
CREATE TABLE table1
(
id INT,
employee VARCHAR(32)
);
CREATE TABLE table2
(
id INT,
person VARCHAR(32)
);
INSERT INTO table1
SELECT a.id,a.person FROM (
INSERT table2
OUTPUT INSERTED.id,INSERTED.person
VALUES(1,'Ada')
) AS a
GO