【问题标题】:I want to Rebuild data table from a sorted table我想从排序表重建数据表
【发布时间】:2014-07-26 22:50:28
【问题描述】:

好的,首先介绍一下背景知识,我继承了在 MSSQL 2000 上维护数据库的经验。

在数据库中有大量通过外键相互关联的表。

我正在尝试以排序方式重建每个表,以消除表的 IDENT 列中的间隙。

特别是在一张桌子上,我有以下列:

RL_ID、RL_FK_RaidID、RL_FK_MemberID、RL_FK_ItemID、RL_ItemValue、RL_Notes、RL_IsUber、RL_IsWishItem、RL_LootModifier、RL_WishItemValue、RL_WeightedLootValue

它使用 RL_ID 作为 IDENT 列,当前使用 DBCC CHECKIDENT (Table) 报告 32620 但是,此表中只有 12128 行信息。

所以我尝试了一个简单的脚本,将所有信息以排序方式复制到一个新表中:

INSERT INTO Table_1

SELECT     RL_ID, RL_FK_RaidID, RL_FK_MemberID, RL_FK_ItemID, RL_ItemValue, RL_Notes, RL_IsUber, RL_IsWishItem, RL_LootModifier, RL_WishItemValue, RL_WeightedLootValue

FROM         RaidLoot

ORDER BY RL_ID

然后从源表中删除所有行:

TRUNCATE TABLE (RaidLoot)

验证 IDENT 是否为 1:

DBCC CHECKIDENT (RaidLoot)

现在将数据从第 1 行复制回原始表到最后:

SET IDENTITY_INSERT RaidLoot ON

INSERT INTO RaidLoot (RL_ID, RL_FK_RaidID, RL_FK_MemberID, RL_FK_ItemID, RL_ItemValue, RL_Notes, RL_IsUber, RL_IsWishItem, RL_LootModifier, RL_WishItemValue, RL_WeightedLootValue)

SELECT RL_ID, RL_FK_RaidID, RL_FK_MemberID, RL_FK_ItemID, RL_ItemValue, RL_Notes, RL_IsUber, RL_IsWishItem, RL_LootModifier, RL_WishItemValue, RL_WeightedLootValue

FROM         Table_1

ORDER BY RL_ID

SET IDENTITY_INSERT RaidLoot OFF

现在验证我只有 12128 行数据:

DBCC CHECKIDENT (RaidLoot)

(注意:我再次以 32620 结束,因为它从未重新编号 RL_ID,它只是将它们放回相同的位置,留下空白)。那么我在哪里/如何让它从 1 开始重新编号 RL_ID 列,以便当它将数据写回原始表时我没有间隙?

我能看到的唯一其他解决方案是在将 Table_1 中的每一行 RL_ID 写回原始表之前手动更改它的心痛过程。虽然这并非不可能。我有另一个表,其中包含大约 306,000 行数据,但 IDENT 报告列出的数据为 450,123,因此我希望有一种更简单的方法来自动化重新编号过程。

【问题讨论】:

  • 很可能 RL_ID 被架构中的其他表引用,为了更改它,您需要更新这些引用。这可能是一件苦差事。留下空白有什么问题?
  • @Andreas,我的想法完全正确。虽然我很感激想要重新开始并使用 min int 而不是 0 来使记录翻倍。无论哪种方式,如果您接近限制 2,147,483,647,您可能还有其他问题需要担心 - 除了不连续的数字
  • @DanAndrews,好的,除非我必须将所有单独的 IDENT 列相加,否则我离 2,147,483,647 还很远。感谢您的回复。

标签: sql sql-server database sql-server-2000


【解决方案1】:

如果您真的必须这样做(对我来说似乎是在浪费时间),您还必须调整所有外键引用。

考虑为每个表添加一个 NewID 列并按顺序填充新列的策略。然后,您可以在调整外键所需的查询中使用此 NewID 列。除非你能想出一个一致的模式来这样做,否则非常混乱。

由于您可以查询元数据以确定外键等,这当然是可能的,如果您确实有很多表,绝对应该认真考虑。

添加

There is a simple way to populate the NewID column

declare @id int
set @id = 0
update MyTable set NewID=@id, @id=@id+1

这并不明显,但确实有效。

【讨论】:

  • @Gary 谢谢 Gary,感谢您的建议
  • 添加了填充 newid 列的方法
【解决方案2】:

我认为这与 RL_ID 被架构中的其他表引用无关 - 如果我设置单个表测试,身份将始终显示为身份字段中的最大数量:

CREATE TABLE #temp (id INT IDENTITY(1,1), other VARCHAR(1))

INSERT INTO #temp
        ( other )
VALUES  (  -- id - int
          'a'  -- other - varchar(1)
          ),('b'),('c'),('d'),('e')

SELECT *
FROM #temp

SELECT *
INTO #holder
FROM #temp
WHERE other = 'C'

TRUNCATE TABLE #temp

SET IDENTITY_INSERT #temp ON

INSERT INTO #temp
        ( id, other )
SELECT  id ,
        other
FROM #holder

DBCC CHECKIDENT (#temp)

DROP TABLE #temp
DROP TABLE #holder

所以你的新身份是 32620,因为那是 MAX(RL_ID)

【讨论】:

    猜你喜欢
    • 2018-07-30
    • 2021-08-27
    • 2021-12-17
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多