将子行移至新的父 FK ID?
SQL Server 2008。
我有一个 pk id 1 的父行。在阻止所有其他数据库用户时(这是一个清理操作,因此资源争用不是问题),我想插入一个新行,然后获取所有子行rows 并将其 fk 列更改为新行。以下面的 DDL 为例,我想插入一个新行并为所有 #chi.parid 值赋予值“3”,这样它们现在基本上属于新行,以便可以删除旧行。
帮助!
create table #par ( parid int identity(1,1) , note varchar(8) )
create table #chi ( chiid int identity(1,1) , parid int , thing varchar(8) )
insert into #par values ( 'note1' )
insert into #par values ( 'note2' )
insert into #chi values ( 1 , 'a' )
insert into #chi values ( 1 , 'b' )
insert into #chi values ( 1 , 'c' )
SQL Server 2008.
I have a parent row with pk id 1. While blocking all other DB users (this is a cleanup operation so resource contention is not an issue), I would like to insert a new row, then take all of the child rows and change their fk column to the new row. With the below DDL for example, I would like to insert a new row and give all of the #chi.parid values a value of '3' so they would essentially now belong to the new row so the old one can be deleted.
Help!
create table #par ( parid int identity(1,1) , note varchar(8) )
create table #chi ( chiid int identity(1,1) , parid int , thing varchar(8) )
insert into #par values ( 'note1' )
insert into #par values ( 'note2' )
insert into #chi values ( 1 , 'a' )
insert into #chi values ( 1 , 'b' )
insert into #chi values ( 1 , 'c' )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我倾向于避免使用代理键,而倾向于使用自然键或 FK;另外,我会避免使用 IDENTITY 作为人工标识符。老实说,我发现自己属于少数派,并且经常想知道如何使用
IDENTITY
FK 实现批量插入。根据 Alan Barker 的回答,您可以使用 SCOPE_IDENTITY(),但前提是您想要执行此 RBAR(逐行执行)。你说,“这是一个清理操作”,所以也许程序解决方案是可以接受的。
我自己解决这个问题的方法是手动生成一系列潜在的 IDENTITY 值(例如在临时表中),然后使用 SET IDENTITY_INSERT TargetTable ON 强制显然,我需要确保在发生 INSERT 时建议的值实际上不会被使用,因此仍然需要阻止所有其他用户。
有几件事值得关注。有时,
IDENTITY
列上的强制性UNIQUE
约束缺失,因此您可能需要自己检查是否存在冲突。另外,我发现,当值不连续(并且在正范围内!)时,喜欢代理的人可能会有点“慌乱”,或者更糟糕的是,存在依赖于完美的应用程序逻辑序列或已将 IDENTITY 值暴露给业务(在这种情况下,“伪造”企业关键值(例如订单号)可能会落入现实生活中的审计员手中)。编辑:今天早上阅读另一个SO问题的答案让我想起了SQL Server 2008的
OUTPUT
子句来捕获表中所有自动生成的IDENTITY
值,例如I tend to shun surrogate keys in favour of natural keys or FKs; also, I would avoid
IDENTITY
for artificial identifiers. To be honest, I find myself in the minority and have often wondered myself how to achieve bulk inserts withIDENTITY
FKs.As per Alan Barker's answer, you can utilize
SCOPE_IDENTITY()
but only if you want to do this RBAR (row by agonizing row). You say, "this is a cleanup operation" so perhaps a procedural solution is acceptable.The way I've got around the problem myself is to manually generate a sequence of potential
IDENTITY
values (e.g. in a staging table) then useSET IDENTITY_INSERT TargetTable ON
to force the values in. Obviously, I need to ensure the proposed values will not actually be in use by the time theINSERT
occurs so all other users will still need to be blocked.A couple of things to watch. Sometimes the obligatory
UNIQUE
constraint on theIDENTITY
column is missing so you may need to check there are no collisions yourself. Also, I've found that the kind of person who likes surrogates can get a bit 'flustered' when the values aren't sequential (and in the positive range!) or, much worse, there is application logic that relies on a perfect sequence or has exposed theIDENTITY
values to the business (in which case 'faking' enterprise key values such as order numbers can fall fowl of real life auditors).EDIT: reading an answer to another SO question this morning reminded me about SQL Server 2008's
OUTPUT
clause to capture all the auto-generatedIDENTITY
values in a table e.g.我认为您只是想要更新,例如:
FKeys 不应该成为这里的问题。
I think you just want an update, such as :
FKeys shouldn't be an issue here.
除了 Kalium 的解决方案之外,您可以使用 SCOPE_IDENTITY() 函数来检索最后一个表插入的 IDENTITY 值。
这样您就可以将其编码为存储过程来完成整个事情:
然后简单地:
Further to Kalium's solution, you could use the SCOPE_IDENTITY() function to retrieve the IDENTITY value of the last table insert.
This way you could code this as a Stored Procedure to do the whole thing:
And then simply:
那么在这种情况下你可以简单地使用游标。性能不是最好的,但看起来这是一项停机清理工作:
Well in that case you could simply use a Cursor. Not the best for performance but looks like this is a downtime-clean up job anyway:
感谢大家的意见。看来我“不能”使用 SQL Svr 2008 对此进行基于集合的操作,因此我使用循环进行了 RBAR 解决方案(我认为它的性能比游标更好)。任何可以评论如何使用 try..catch 使其更安全或启发我更多如何在集合中执行此操作的人,请发表评论。 :)
谢谢。
Thanks all for the input. It appears I "can't" do a set-based operation on this with SQL Svr 2008, so I did RBAR solution with a loop (I think it performs better than a cursor). Anyone who can comment on making this safer with try..catch or enlighten me more on doing this in a set, please comment. :)
Thanks.