[英]INSERT into table and UPDATE foreign key in another table (Sql Server 2008)
I have two tables, TableA
and TableB
like this: 我有两个表, TableA
和TableB
像这样:
TableA
-------------------------------------------
| id | some_data | new_FK_column_on_B |
| ---- | ----------- | ------------------ |
| 1 | ... | null |
| ... | ... | null |
| 999 | ... | null |
-------------------------------------------
TableB
----------------------------
| id | some_other_data |
| ---- | ----------------- |
| | |
----------------------------
At the moment, TableB
is empty, and FK column in TableA
is null
for all rows. 目前, TableB
为空, TableA
FK列对所有行都为null
。 I need to write one-time initializing scrit to populate TableB
and initialize FK column for some rows (criterial, not for all) in TableA
by identifiers from rows, inserted in TableB
. 我需要一次性初始化scrit填充写TableB
和初始化一些行(严格标准,不是所有)在FK列TableA
的标识从行插入TableB
。
I know two ways to do this: 我知道有两种方法可以做到这一点:
1) using while
and scope_identity()
, inserting new row into TableB
and updating TableA
on each iteration, while exists rows in TableA
, which should be updated 1)使用while
和scope_identity()
,在TableB
插入新行并在每次迭代时更新TableA
,同时在TableA
存在行,应该更新
while (exists (select 1 from TableA where [condition]))
begin
insert into TableB (some_other_data) values ('some_other_data')
update TableA set new_FK_column_on_B
where id = (select top 1 id from TableA where [condition])
end
2) create temp column in TableB
, storing id
of row in TableA
, for which it was inserted, and then update TableA
using join
2)在TableB
创建临时列,在TableA
存储行的id
,为其插入,然后使用join
更新TableA
alter table TableB add temp int
go
insert into TableB (some_other_data, temp) select 'some_other_data', id from TableA where [condition]
update TableA
set new_FK_column_on_B = b.id
from TableB as b
join TableA as a on a.id = b.temp
alter table TableB drop column temp
Also I was trying to use somehow output
from insert
like this, but it's syntax is incorrect: 另外我试图以某种方式使用insert
output
,但它的语法不正确:
update TableA
set new_FK_column_on_B =
(
select insertedId from
(
insert into TableB (some_other_data)
output inserter.id as insertedId
values ('some_other_data')
)
)
where [condition]
Is there any easier way to do this whithout using while
or modifing any table? 有没有更简单的方法来做这个while
使用或修改任何表?
I found this question when searching for a solution a similar case. 在寻找类似案例的解决方案时,我发现了这个问题。 The only difference was that I wanted to fill TableB with an row for each row in TableA (no where-clause). 唯一的区别是我想用TableA中的每一行填充TableB(没有where子句)。
I found a solution to the third option you suggeted (using output from insert), however, since you are using INSERT with data from a SELECT, you cannot use the OUTPUT clause. 我找到了你建议的第三个选项的解决方案(使用insert的输出),但是,由于你使用INSERT和SELECT中的数据,你不能使用OUTPUT子句。 This pointed me in the right direction: 这使我指出了正确的方向:
DECLARE @MyTableVar table(tableBId int, tableAId int)
MERGE INTO TableB
using TableA AS AP
on 1=0
WHEN NOT MATCHED THEN
Insert(some_other_data)
Values('some_other_data')
Output inserted.ID, AP.ID INTO @MyTableVar;
update TableA set new_FK_column_on_B = (select tableBId from @MyTableVar where tableAId = TableA.ID)
Be aware that executing this a seconds time will create new entries in TableB. 请注意,执行此秒时间将在TableB中创建新条目。 If you only want to create new rows in TableB, where there is no foreign key set in TableA, you can use this script: 如果您只想在TableB中创建新行,而TableA中没有设置外键,则可以使用此脚本:
DECLARE @MyTableVar TABLE(tableBId int, tableAId int)
MERGE INTO TableB AS B
USING TableA AS AP
ON A.new_FK_column_on_B = B.id
WHEN NOT MATCHED THEN
INSERT(some_data)
VALUES(AP.some_data)
OUTPUT inserted.ID, AP.ID INTO @MyTableVar;
UPDATE TableA SET new_FK_column_on_B = (
SELECT tableBId
FROM @MyTableVar
WHERE tableAId = TableA.ID )
WHERE TableA.new_FK_column_on_B IS NULL;
You can do all this as set operations: 你可以做所有这些作为设置操作:
insert into b(some_data)
select distinct some_data
from a;
update a
set new_FK_column_on_B = b.id
from a join
b
on a.some_data = b.some_data;
This assumes that the id
column in b
is declared as identity()
, so it gets assigned automatically. 这假设b
中的id
列声明为identity()
,因此它会自动分配。 This is a good idea, but if you want to do this manually, then the first query would be something like: 这是一个好主意,但如果你想手动完成,那么第一个查询就像:
insert into b(some_data)
select row_number() over (order by (select null)), some_data
from (select distinct some_data
from a
) a;
There is no need for a while
loop. 不需要while
循环。
DISCLAIMER: This is not tested at all, I wrote this in notepad: 免责声明:我没有经过测试,我在记事本中写道:
DECLARE @TableAValues TABLE (IdTableA int, SomeData varchar)
INSERT INTO @TableAValues(IdTableA, SomeData)
SELECT id, 'some_data' FROM TableA
DECLARE @TableBIds TABLE (IdTableB int)
INSERT INTO TableB(SomeData)
OUTPUT INSERTED.ID INTO @TableBIds
SELECT SomeData FROM @TableAValues
UPDATE ta
SET ta.new_FK_column_on_B = tbi.IdTableB
FROM dbo.TableA AS ta
INNER JOIN @TableAValues AS tav ON ta.id = tav.IdTableA -- used in case more records were added to table in the interim.
LEFT OUTER JOIN @TableBIds tbi On tav.RowNum = tbi.RowNum
Note: I am using In memory tables, but if you were concerned about memory usage, you could probably just switch those out for temp tables on disk. 注意:我在内存表中使用,但是如果你担心内存使用情况,你可能只需将它们转换为磁盘上的临时表。
The idea I was going for here: 我想去的想法:
I'd be very surprised if my code sample above works as is, but hopefully the idea will be useful, if not my execution. 如果上面的代码示例按原样工作,我会非常惊讶,但希望这个想法有用,如果不是我的执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.