将 sql 2000 备份恢复到 sql 2008 后,使用 IDENTITY 列的过程因主键冲突而失败

发布于 2024-09-10 16:26:38 字数 1436 浏览 2 评论 0原文

我刚刚将数据库从 SQL 2000 实例移至 SQL 2008 实例,并遇到了一个奇怪的问题,该问题似乎与 IDENTITY 列和存储过程有关。

我在数据库中有许多存储过程,

create procedure usp_add_something @somethingId int, @somethingName nvarchar(100)
with encryption
as

-- If there's an ID then update the record
if @somethingId <> -1 begin

 UPDATE  something  SET somethingName = @somethingName

end else begin

 -- Add a new record
 INSERT INTO something ( somethingName )  VALUES ( @somethingName )

end

go

这些存储过程都是作为加密存储过程创建的。 id 列(例如本例中的somethingId)是一个带有主键的IDENTITY(1,1),并且这些表中有很多行。

恢复到 SQL 2008 实例后,我的许多数据库似乎工作正常,但类似的调用会

exec usp_add_something @somethingId = -1, @somethingName = 'A Name'

导致如下错误:

违反主键约束“Something_PK”。无法在对象“dbo.something”中插入重复的键。

似乎有些事情搞砸了,导致 SQL Server 无法正确分配下一个 IDENTITY...或类似的情况。这很奇怪!

我可以直接 INSERT 到表中,而无需指定 id 列,并且它会为标识列分配一个 id 。

没有 SomethingId = -1 的记录...但这并不会有任何区别。

如果我删除并重新创建该过程,问题就会消失。但我有很多这样的过程,所以不想这样做,以防万一我错过了一些过程,或者数据库中有一个自定义过程被我覆盖。

有谁知道与此相关的任何已知问题? (以及理想的解决方案!)

是否有其他方法可以将我的 sql 2000 数据库移动到 sql 2008 实例?例如,Detach 和 Attach 的行为是否可能不同?

我尝试使用 sp_recompile 'usp_add_something' 重新编译该过程,但这并没有解决问题,所以我不能简单地在所有过程上调用它。

感谢您的任何帮助

R

(交叉发布 此处

I've just moved a database from a SQL 2000 instance to a SQL 2008 instance and have encountered an odd problem which appears to be related to IDENTITY columns and stored procedures.

I have a number of stored procedures in the database along the lines of this

create procedure usp_add_something @somethingId int, @somethingName nvarchar(100)
with encryption
as

-- If there's an ID then update the record
if @somethingId <> -1 begin

 UPDATE  something  SET somethingName = @somethingName

end else begin

 -- Add a new record
 INSERT INTO something ( somethingName )  VALUES ( @somethingName )

end

go

These are all created as ENCRYPTED stored procedures. The id column (e.g. somethingId in this example) is an IDENTITY(1,1) with a PRIMARY KEY on it, and there are lots of rows in these tables.

Upon restoring onto the SQL 2008 instance a lot of my database seems to be working fine, but calls like

exec usp_add_something @somethingId = -1, @somethingName = 'A Name'

result in an error like this:

Violation of PRIMARY KEY constraint 'Something_PK'. Cannot insert duplicate key in object 'dbo.something'.

It seems that something is messed up that either causes SQL Server to not allocate the next IDENTITY correctly...or something like that. This is very odd!

I'm able to INSERT into the table directly without specifying the id column and it allocates an id just fine for the identity column.

There are no records with somethingId = -1 ... not that that should make any difference.

If I drop and recreate the procedure the problem goes away. But I have lots of these procedures so don't really want to do that in case I miss some or there is a customized procedure in the database that I overwrite.

Does anyone know of any known issues to do with this? (and a solution ideally!)

Is there a different way I should be moving my sql 2000 database to the sql 2008 instance? e.g. is it likely that Detach and Attach would behave differently?

I've tried recompiling the procedure using sp_recompile 'usp_add_something' but that didn't solve the problem, so I can't simply call that on all procedures.

thanks for any help

R

(cross-posted here)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烟织青萝梦 2024-09-17 16:26:38

如果问题是身份种子设置不正确,您可以通过以下方式重置表:

DBCC CHECKIDENT (TableName, RESEED, 0);
DBCC CHECKIDENT (TableName, RESEED);

这将自动查找表中的最高值并适当设置种子,因此您不必执行 SELECT Max()< /代码> 查询。现在修复表可以自动化完成,无需动态 SQL 或手动编写脚本。

但你说你可以直接插入到表中没有问题,所以这可能不是问题。但我想发帖澄清重置身份种子的简单方法。

注意:如果您的表格增量为负数,或者您过去重置种子以在消耗完所有正数后从最低的开始用完所有负数,则所有投注均无效。特别是在后一种情况下(具有正增量,但您使用的标识值低于表中已有的其他值),则您不想运行DBCC CHECKIDENTcode> 而不指定 NORESEED 曾经。因为仅仅 DBCC CHECKIDENT (TableName); 就会搞砸您的身份值。您必须使用DBCC CHECKIDENT (TableName, NORESEED)。如果你忘记了这一点,有趣的时光就会随之而来。 :)

If the problem is an improperly set identity seed, you can reset a table this way:

DBCC CHECKIDENT (TableName, RESEED, 0);
DBCC CHECKIDENT (TableName, RESEED);

This will automatically find the highest value in the table and set the seed appropriately so you don't have to do a SELECT Max() query. Now fixing the table can be done in automation, without dynamic SQL or manual script writing.

But you said you can insert to the table directly without a problem, so it's probably not the issue. But I wanted to post to set the record straight about the easy way to reset the identity seed.

Note: if your table's increment is negative, or you in the past reset the seed to use up all negative numbers starting at the lowest after consuming all the positive numbers, all bets are off. Especially in the latter case (having a positive increment, but you are using identity values lower than others already in the table), then you do not want to run DBCC CHECKIDENT without specifying NORESEED ever. Because just DBCC CHECKIDENT (TableName); will screw up your identity value. You must use DBCC CHECKIDENT (TableName, NORESEED). Fun times will ensue if you forget this. :)

悸初 2024-09-17 16:26:38

首先,检查表中的最大 ID:

select max(id_column) from YourTable

然后,检查当前身份种子:

select ident_seed('YourTable')

如果当前种子低于最大值,请使用 dbcc checkident 为表重新设定种子:

DBCC CHECKIDENT (YourTable, RESEED, 42)

其中 42 是当前最大值。

有关如何出错的演示代码:

create table YourTable (id int identity primary key, name varchar(25))
DBCC CHECKIDENT (YourTable, RESEED, 42)
insert into YourTable (name) values ('Zaphod Beeblebrox')
DBCC CHECKIDENT (YourTable, RESEED, 41)
insert into YourTable (name) values ('Ford Prefect') --> Violation of PRIMARY KEY

First, check the maximum ID from your table:

select max(id_column) from YourTable

Then, check the current identity seed:

select ident_seed('YourTable')

If the current seed is lower than the maximum, reseed the table with dbcc checkident:

DBCC CHECKIDENT (YourTable, RESEED, 42)

Where 42 is the current maximum.

Demonstration code for how this can go wrong:

create table YourTable (id int identity primary key, name varchar(25))
DBCC CHECKIDENT (YourTable, RESEED, 42)
insert into YourTable (name) values ('Zaphod Beeblebrox')
DBCC CHECKIDENT (YourTable, RESEED, 41)
insert into YourTable (name) values ('Ford Prefect') --> Violation of PRIMARY KEY
白馒头 2024-09-17 16:26:38

我尝试过,但无法在另一台服务器上复制此内容。

然而,在我的实时服务器上,我从 sql 2008 中删除了有问题的数据库,并使用分离和重新附加重新创建了它,这工作很好,没有这些主键违规错误。

由于我想让原始数据库保持活动状态,实际上我的具体步骤是:

  • 在同一实例上备份 sourceDb 并恢复为 sourceDbCopy

  • take sourceDbCopy 离线

  • 将sourceDbCopy 文件移动到新服务器

  • 附加数据库

  • 重命名数据库改为原来的名称

I tried and was unable to replicate this on another server.

However, on my Live servers I dropped the problem database from sql 2008 and recreated it using a detach and reattach and this worked fine, without these PRIMARY KEY VIOLATION errors.

Since I wanted to keep the original database live, in fact my exact steps were:

  • back up sourceDb and restore as sourceDbCopy on the same instance

  • take sourceDbCopy offline

  • move the sourceDbCopy files to the new server

  • attach the database

  • rename the database to the original name

素年丶 2024-09-17 16:26:38

如果重新创建程序有帮助,这里有一个生成重新创建脚本的简单方法:

  1. 右键单击数据库 ->任务->生成脚本
  2. 在第 2 页(“选择对象”)上选择存储过程
  3. 在第 3 页(“设置脚本选项”)上选择“高级”->“存储过程”编写 DROP 和 CREATE 脚本并将其设置为 Script DROP and CREATE。
  4. 将脚本保存在某处并运行

If recreating the procedures helps, here's an easy way to generate a recreation script:

  1. Right click database -> Tasks -> Generate scripts
  2. On page 2 ("Choose Objects") select the stored procedures
  3. On page 3 ("set scripting options") choose Advanced -> Script DROP and CREATE and set it to Script DROP and CREATE.
  4. Save the script somewhere and run it
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文