将所有主键值增加 1

dus*_*orn 7 sql-server-2008 database-design

EmployeeID如果它是主键,我如何将所有值加一?

Seb*_*ine 10

我假设这个问题是关于如何将一堆行更新为更高的值而不相互踩踏。如果您将第一行中的 id=1 更新为 id=2,而第二行(id=2)仍然存在,您将得到主键违规,因为现在您有两行 id=2。

为了防止这种类型的碰撞,您只需要从最大值开始并将其增加一。这为第二大值开辟了一个缺口,而这又为第三大值开辟了一个缺口,依此类推。

然而,在 SQL Server 中,您不必担心,因为引擎会自动处理:

SQL小提琴

MS SQL Server 2008 架构设置

CREATE TABLE dbo.Employee(Id INT PRIMARY KEY CLUSTERED, Name NVARCHAR(MAX));

INSERT INTO dbo.Employee(Id,Name)
VALUES(1,'John'),(2,'Jane'),(3,'Max');
Run Code Online (Sandbox Code Playgroud)

查询 1

SELECT * FROM dbo.Employee;
Run Code Online (Sandbox Code Playgroud)

结果

| ID | NAME |
|----|------|
|  1 | John |
|  2 | Jane |
|  3 |  Max |
Run Code Online (Sandbox Code Playgroud)

查询 2

UPDATE dbo.Employee
  SET Id = Id + 1;
Run Code Online (Sandbox Code Playgroud)

执行计划

查询 3

SELECT * FROM dbo.Employee;
Run Code Online (Sandbox Code Playgroud)

结果

| ID | NAME |
|----|------|
|  2 | John |
|  3 | Jane |
|  4 |  Max |
Run Code Online (Sandbox Code Playgroud)

查询 4

UPDATE dbo.Employee
  SET Id = Id - 1;
Run Code Online (Sandbox Code Playgroud)

执行计划

查询 5

SELECT * FROM dbo.Employee;
Run Code Online (Sandbox Code Playgroud)

结果

| ID | NAME |
|----|------|
|  1 | John |
|  2 | Jane |
|  3 |  Max |
Run Code Online (Sandbox Code Playgroud)

如果你真的按照SQL Fiddle链接,你还可以看到两个更新语句的执行计划。第一个看起来像这样:

在此处输入图片说明

在那里,您可以在左侧相当远的地方看到一个Table Spool操作员。该运算符基本上创建了所有行的副本,这些行在被旁边的实际“聚集索引更新”运算符写回之前已更新。因此,SQL Server 能够处理“重叠”更新而不会被自身绊倒。

一个额外的好处(以及实施此行为的最初原因)是这两个步骤的方法提供了万圣节保护

  • 需要表假脱机,因为名称列是 LOB 类型。使用非 LOB 名称,排序为 HP 提供了足够的相分离。Split-Sort-Collapse 优化了日志记录并确保按顺序应用更改,以防止暂时违反密钥。 (2认同)
  • 我不得不检查,但是是的!我在 [这篇文章](https://sqlkiwi.blogspot.com/2010/12/beware-sneaky-reads-with-unique-indexes.html) 和 [四部分] 中讨论了万圣节保护系列](https://sqlkiwi.blogspot.com/2013/02/halloween-protection-the-complete-series.html)。Conor Cunningham 在 MS Press 出版的 SQL Server 2008 Internals 一书中谈到了日志优化。 (2认同)

Dav*_*ett 5

如果没有关于数据库结构的更多详细信息,这里有大量变量。

如果任何其他包含员工 ID 的表作为对该表的引用,并且外键被正确设置并设置为,那么ON UPDATE CASCADE只需执行UPDATE EmployeeTable SET EmployeeID = EmployeeID + 1即可完成任务 - FK 关系将根据需要更新其他所有内容。如果没有ON UPDATE CASCADE这种情况,您将收到错误并且语句将失败。

如果您有引用员工 ID 且不存在外键约束的表,那么您也必须使用 来更新这些表UPDATE AnotherTable SET EmployeeID = EmployeeID + 1。您应该将所有表更新包装在单个事务中(使用错误处理来确保事务回滚,或者SET XACT_ABORT ON如果您不需要对该过程进行任何更精细的控制)以保持一致性(因此,如果出现故障,则所有内容都会回滚)后退)。

我想问你为什么要这样做。员工标识符通常是一个代理键(也称为伪键),除了识别给定人员之外没有任何意义(它很可能是 UUID 而不是数字,除了它可能用于现实世界中的书面形式之外)下来,所以 UUID 不太方便)。有关于此的更多讨论,请参阅 SQL Antipatterns 中的“psuedo-key clean-freak”一章。