我的数据库包含三个名为Object_Table
,Data_Table
和Link_Table
的表格。链接表只包含两列,即对象记录的标识和数据记录的标识。
我希望将DATA_TABLE
中的数据复制到一个给定的对象标识,并将相应的记录插入Data_Table
和Link_Table
以获取不同的给定对象标识。
我可以通过选择一个表变量并循环为每次迭代执行两次插入来完成此操作。
这是最好的方法吗?
编辑:我想避免循环有两个原因,第一个是我很懒,循环/临时表需要更多代码,更多代码意味着更多地方犯错误第二个原因是对性能的关注。
我可以将所有数据复制到一个插入中,但如何将链接表链接到每个记录都有新ID的新数据记录?
答案 0 :(得分:202)
在一个声明中:否。
在一个交易中:是
BEGIN TRANSACTION
DECLARE @DataID int;
INSERT INTO DataTable (Column1 ...) VALUES (....);
SELECT @DataID = scope_identity();
INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT
好消息是上面的代码也保证是 atomic ,并且可以从一个客户端应用程序发送到服务器,在一个函数调用中只有一个sql字符串,就像它是一个声明。您还可以将触发器应用于一个表以获得单个插入的效果。但是,它最终仍然是两个语句,您可能不希望为每个插入运行触发器。
答案 1 :(得分:31)
您仍然需要两个INSERT
语句,但听起来您希望从第一个插入中获取IDENTITY
并在第二个插入中使用它,在这种情况下,您可能需要查看{ {1}}或OUTPUT
:http://msdn.microsoft.com/en-us/library/ms177564.aspx
答案 2 :(得分: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
感谢另一个answer向我指出了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子句无法启用 a的任何一方(主键,外国 关键)关系
我仍然可以OUTPUT INTO
临时表,然后使用普通插入完成。所以我可以避免我的循环,但我无法避免临时表。
答案 3 :(得分:6)
听起来Link表捕获了Object表和Data表之间的许多关系。
我的建议是使用存储过程来管理事务。如果要插入Object或Data表执行插入,请获取新ID并将其插入Link表。
这允许所有逻辑保持封装在一个易于调用的sproc中。
答案 4 :(得分:4)
如果您希望操作或多或少是原子的,我会确保将它们包装在事务中。这样你可以确定两者都发生了,或者两者都没有按需发生。
答案 5 :(得分:4)
您可以创建一个视图,选择insert语句所需的列名,添加一个INSTEAD OF INSERT触发器,然后插入到该视图中。
答案 6 :(得分:4)
我想强调使用
SET XACT_ABORT ON;
用于具有多个sql语句的MSSQL事务。
请参阅: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
答案 7 :(得分:2)
插入只能一次在一个表上运行。多个插入必须有多个语句。
我不知道你需要通过表变量进行循环 - 你不能只在一个表中使用质量插入,然后将质量插入到另一个表中吗?
顺便说一下 - 我猜你的意思是从Object_Table复制数据;否则这个问题没有意义。
答案 8 :(得分:2)
在能够在Oracle中执行多表插入之前,您可以使用涉及插入到视图中的技巧,该视图上定义了INSTEAD OF触发器以执行插入。可以在SQL Server中完成吗?
答案 9 :(得分:-1)
<canvas id="game" width="500px" height="500px">
Please get a new browser!
</canvas>
<button onclick="restart()">Opnieuw!</button>
答案 10 :(得分:-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张桌子。