SQLServer: 是否可以同时插入到两个表中?

我的数据库包含三个表,分别是 Object_TableData_TableLink_Table。链接表只包含两列,一个是对象记录的标识,另一个是数据记录的标识。

我想从 DATA_TABLE中复制数据,将其链接到一个给定的对象标识,并为不同的给定对象标识向 Data_TableLink_Table中插入相应的记录。

可以通过选择一个表变量并通过为每次迭代执行两次插入来进行循环来完成这项工作。

这是最好的办法吗?

编辑 : 我想避免循环有两个原因,第一个原因是我懒惰,循环/临时表需要更多的代码,更多的代码意味着更多的地方犯错误,第二个原因是对性能的关注。

我可以在一次插入中复制所有数据,但是如何让链接表链接到每个记录都有新 ID 的新数据记录呢?

412752 次浏览

如果您希望操作多多少少是原子的,那么我将确保将它们包装在事务中。这样你就可以确定两者都发生了,或者两者都没有发生。

Insert 一次只能对一个表进行操作。多个 Inserts 必须有多个语句。

我不知道你是否需要通过一个表变量来进行循环——难道你不能在一个表中使用一个巨大的插入,然后将巨大的插入放到另一个表中吗?

顺便说一下-我猜你的意思是从 Object _ Table 复制数据; 否则这个问题就没有意义了。

您仍然需要两个 INSERT语句,但是听起来您希望从第一个插入获取 IDENTITY并在第二个插入中使用它,在这种情况下,您可能需要查看 OUTPUTOUTPUT INTO: http://msdn.microsoft.com/en-us/library/ms177564.aspx

不。

是的

BEGIN TRANSACTION
DECLARE @DataID int;
INSERT INTO DataTable (Column1 ...) VALUES (....);
SELECT @DataID = scope_identity();
INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

好消息是,上面的代码也保证是 原子弹,并且可以从客户机应用程序用一个 sql 字符串在一个函数调用中发送到服务器,就好像它是一条语句一样。还可以对一个表应用触发器以获得单次插入的效果。但是,它最终仍然是两个语句,您可能不想为 每个插入运行触发器。

这听起来好像 Link 表捕获了 Object 表和 Data 表之间的多: many 关系。

我的建议是使用存储过程来管理事务。当要插入 Object 或 Data 表时,请执行插入操作,获取新的 ID 并将它们插入 Link 表。

这允许将所有逻辑封装在一个易于调用的 sproc 中。

您可以创建一个选择插入语句所需的列名的视图,添加一个 INSTEADOFINSERT 触发器,然后插入到这个视图中。

在能够在 Oracle 中执行多表插入之前,您可以使用一个技巧,涉及将插入操作插入到一个定义了 INSTEADOF 触发器的视图中来执行插入操作。这可以在 SQLServer 中完成吗?

下面使用表变量设置我的情况。

DECLARE @Object_Table TABLE
(
Id INT NOT NULL PRIMARY KEY
)


DECLARE @Link_Table TABLE
(
ObjectId INT NOT NULL,
DataId INT NOT NULL
)


DECLARE @Data_Table TABLE
(
Id INT NOT NULL Identity(1,1),
Data VARCHAR(50) NOT NULL
)


-- create two objects '1' and '2'
INSERT INTO @Object_Table (Id) VALUES (1)
INSERT INTO @Object_Table (Id) VALUES (2)


-- create some data
INSERT INTO @Data_Table (Data) VALUES ('Data One')
INSERT INTO @Data_Table (Data) VALUES ('Data Two')


-- link all data to first object
INSERT INTO @Link_Table (ObjectId, DataId)
SELECT Objects.Id, Data.Id
FROM @Object_Table AS Objects, @Data_Table AS Data
WHERE Objects.Id = 1

由于另一个 回答指出了 OUTPUT 条款,我可以展示一个解决方案:

-- now I want to copy the data from from object 1 to object 2 without looping
INSERT INTO @Data_Table (Data)
OUTPUT 2, INSERTED.Id INTO @Link_Table (ObjectId, DataId)
SELECT Data.Data
FROM @Data_Table AS Data INNER JOIN @Link_Table AS Link ON Data.Id = Link.DataId
INNER JOIN @Object_Table AS Objects ON Link.ObjectId = Objects.Id
WHERE Objects.Id = 1

然而,事实证明,在现实生活中,这并不那么简单,因为出现了以下错误

不能打开 OUTPUTINTO 子句 (主键,外键)的任一边 关键)关系

我仍然可以 OUTPUT INTO一个临时表,然后完成正常的插入。所以我可以避免我的循环,但是我不能避免临时表。

//如果要插入与第一个表相同的内容

$qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";


$result = @mysql_query($qry);


$qry2 = "INSERT INTO table2 (one,two, three) VVALUES('$one','$two','$three')";


$result = @mysql_query($qry2);

//或如果要插入表1的某些部分

 $qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";




$result = @mysql_query($qry);


$qry2 = "INSERT INTO table2 (two) VALUES('$two')";


$result = @mysql_query($qry2);

//我知道它看起来太好了,但它的权利,但它的工作,你可以继续添加查询的只是改变

    "$qry"-number and number in @mysql_query($qry"")

我有17张桌子。

-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


ALTER PROCEDURE InsetIntoTwoTable


(
@name nvarchar(50),
@Email nvarchar(50)
)


AS
BEGIN


SET NOCOUNT ON;




insert into dbo.info(name) values (@name)
insert into dbo.login(Email) values (@Email)
END
GO

我想强调使用

SET XACT_ABORT ON;

用于具有多个 sql 语句的 MSSQL 事务。

参见: http://msdn.microsoft.com/en-us/library/ms188792.aspx”rel = “ norefrer”> https://msdn.microsoft.com/en-us/library/ms188792.aspx 他们提供了一个很好的例子。

因此,最终的代码应该如下所示:

SET XACT_ABORT ON;


BEGIN TRANSACTION
DECLARE @DataID int;
INSERT INTO DataTable (Column1 ...) VALUES (....);
SELECT @DataID = scope_identity();
INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT