SQL Server向表中插入数据

使用 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容