SQL Server:是否可以同时插入两个表?


143

我的数据库包含三个表叫Object_TableData_TableLink_Table。链接表仅包含两列,即对象记录的标识和数据记录的标识。

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

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

这是最好的方法吗?

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

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


我对尝试使用一个插入进行操作并没有兴趣,当使用2个插入进行工作时效果很好。您是说要确保两个插入都完成吗?然后,您必须检查此提交/回退指令。
菲利普·格隆迪尔

2
我将对两个插入感到满意,只是需要将其插入链接表中的标识就是在第一个插入中生成的标识。
tpower

Answers:


219

在一个陈述中:不。

一笔交易:是

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

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


2
这就是我一直在寻找的东西。谢谢:)
nandu.com 2011年

33
@Joel,很好的问题。大概有人希望实现另一种现实,而您是坏消息的承担者。;)
Kirk Woll

2
这今天拯救了我的一天:) thanx
Shekhar_Pro 2011年

12
这不能解决问题。他想插入从Object_Table读取的数据。即insert into ... select ...声明。上面的代码如何读取或遍历Object_Table数据。然后,您仍然需要使用asker不想执行的表变量。
hofnarwillie 2013年

8
当然可以解决问题。也许我没有为此编写所有代码,但是OP也没有共享他想复制的所有列。此答案中演示的功能将使OP能够执行他所要求的...运行查询以创建记录,获取新记录的ID,并以原子方式将该ID用于第二条记录。OP已经知道如何进行插入/选择。这是他丢失的那一块。
Joel Coehoorn 2015年

35

您仍然需要两个INSERT语句,但是听起来您想IDENTITY从第一个插入中获取,然后在第二个插入中使用它,在这种情况下,您可能需要查看OUTPUTOUTPUT INTOhttp : //msdn.microsoft.com/zh-我们/图书馆/ms177564.aspx


1
谢谢!我不知道OUTPUT关键字,正是我想要的。+1
雷克斯·摩根

是否可以在一个SQL中使用两次“ OUTPUT INTO”
V.Wu

@ V.Wu我不这么认为,我必须设置一个测试才能看到。
Cade Roux

18

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

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

然而事实证明,由于以下错误,在现实生活中并非如此简单

OUTPUT INTO子句不能位于(主键,外键)关系的任一侧

我仍然可以OUTPUT INTO使用临时表,然后以普通插入方式完成。因此,我可以避免循环,但无法避免临时表。



6

听起来链接表捕获了Object表和Data表之间的many:many关系。

我的建议是使用存储过程来管理事务。当您想插入“对象”或“数据”表时,请执行插入操作,获取新的ID并将其插入到“链接”表中。

这使您所有的逻辑都可以封装在一个易于调用的sproc中。


为什么没有其他人支持您?存储过程是显而易见的最佳方法。将您的答案与Joel Coehoorn的答案结合起来,您将获得最佳答案!
Rhyous 2014年

4

如果您希望这些动作或多或少是原子的,那么请确保将它们包装在事务中。这样,您可以确保根据需要同时发生或未发生。


2
如果将动作包装在事务中,则它们是原子的,而不是“或多或少”的原子。除非您指定,否则不一定保证隔离级别。
Dave Markle

4

您可以创建一个View,选择您的insert语句所需的列名,添加一个INSTEAD OF INSERT触发器,然后插入到该视图中。



2

插入一次只能在一张桌子上操作。多个插入必须具有多个语句。

我不知道您需要遍历一个表变量-您不能只在一个表中使用大容量插入,然后在另一个表中使用大容量插入吗?

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


2

在能够在Oracle中进行多表插入之前,您可以使用一个技巧,该技巧涉及在视图上定义了INSTEAD OF触发器的视图中进行插入,以执行插入操作。可以在SQL Server中完成吗?


-1
-- ================================================
-- 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

你能补充一些解释吗?
凯尔(Kyll)

-2

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

$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);

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

 $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张桌子一直在工作。


如果插入中间出现问题?您的插入内容将不完整。对?如果这样做,您是否有回滚功能来处理它?如果不是,则您的数据完整性有问题。
deepcell

7
-1。这个答案似乎是在PHP中使用MySQL方法。这个问题被标记为sqlsql-server,没有提到MySQL或PHP。
mskfisher 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.