Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server中唯一ID的批量修改_Sql Server_Database_Scripting_Identity - Fatal编程技术网

Sql server SQL Server中唯一ID的批量修改

Sql server SQL Server中唯一ID的批量修改,sql-server,database,scripting,identity,Sql Server,Database,Scripting,Identity,[这是一个有点不寻常的问题,我知道…] 我需要的是一个脚本,它可以将数据库中的每个唯一id值更改为新的id值。问题是,我们的配置表可以在我们的软件实例之间导出,这些实例对现有id敏感。几年前,我们在开发标准配置和客户实例之间设置了足够大的id差距,但现在差距不够大:-例如,当客户导入我们的标准配置时,我们会遇到id冲突 执行以下操作的sql脚本绝对是我们可以做的最简单/最短时间段的事情。例如,固定代码太复杂,容易出错。请注意,我们并没有在这里消除这个问题。仅仅将差距从1000改变为1000000

[这是一个有点不寻常的问题,我知道…]

我需要的是一个脚本,它可以将数据库中的每个唯一id值更改为新的id值。问题是,我们的配置表可以在我们的软件实例之间导出,这些实例对现有id敏感。几年前,我们在开发标准配置和客户实例之间设置了足够大的id差距,但现在差距不够大:-例如,当客户导入我们的标准配置时,我们会遇到id冲突

执行以下操作的sql脚本绝对是我们可以做的最简单/最短时间段的事情。例如,固定代码太复杂,容易出错。请注意,我们并没有在这里消除这个问题。仅仅将差距从1000改变为1000000或更多现有差距需要5年才能填补

我认为最简单的解决办法是:

将我们所有的表都更改为UPDATE\u CASCADE,它们中没有一个是-这将大大简化脚本 使用我们想要的新的最低id创建标识表 对于每个表,在必要时使用identity insert修改器标志将id修改为identity表中的下一个id。也许在处理每个表之后,我们可以重置标识表。 关闭UPDATE_CASCADE,并删除标识表。
有人有这个或部分脚本的脚本吗?。我将投票表决任何有用的东西:。

为什么不在标准配置值中使用负数,而在其他方面继续使用正数?

不幸的是,Sql Server世界中不存在更新级联。我建议对每个表重新设置密钥,执行以下伪代码

BACKUP DATABASE
CHECK BACKUP WORKS!

FOR EACH TABLE TO BE RE-KEYED
   DROP ALL FOREIGN KEY CONSTRAINTS, INDEXES ETC FROM TABLE

   SELECT ID + Number, ALL_OTHER_FIELDS INTO TEMP_TABLE FROM TABLE
   RENAME TABLE OLD_TABLE
   RENAME TEMP_TABLE TABLE

   FOR ALL TABLES REFERENCING THIS TABLE
       UPDATE FOREIGN_KEY_TABLE SET FK_ID = FK_ID + new number
   END FOR

   RE-APPLY FOREIGN KEY CONSTRAINTS, INDEXES ETC FROM TABLE

END FOR
检查它是否仍然有效


这个过程可以通过DMO/SMO对象实现自动化,但根据涉及的表的数量,我认为使用ManagementStudio生成可以编辑的脚本可能会更快。毕竟,您只需要每五年执行一次。

这里我们将介绍SQL 2005的代码。它是巨大的,它是黑客,但它将工作,除非你有一个主键,是一个复合的其他两个主键的情况下

如果有人可以用MrTelly更快的id添加重新编写它,而不需要为每个更新的行从游标构建sql,那么我将把它标记为可接受的答案。如果我没有注意到新的答案,请向上投票-然后我会注意到:

BEGIN TRAN
SET NOCOUNT ON;

DECLARE @newLowId INT
SET @newLowId = 1000000

DECLARE @sql VARCHAR(4000)

--**** SELECT ALL TABLES WITH IDENTITY COLUMNS ****
DECLARE tables  SCROLL CURSOR
FOR 
SELECT '[' + SCHEMA_NAME(schema_id) + '].[' + t.name + ']', c.name
FROM sys.identity_columns c
INNER JOIN sys.objects t
    on c.object_id = t.object_id
WHERE t.type_Desc = 'USER_TABLE'

OPEN tables

DECLARE @Table VARCHAR(100)
DECLARE @IdColumn VARCHAR(100)

CREATE Table #IdTable(
  id INT IDENTITY(1,1),
  s CHAR(1)
)

FETCH FIRST FROM tables
INTO @Table, @IdColumn

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT('
****************** '+@Table+' ******************
')
    --Reset the idtable to the 'low' id mark - remove this line if you want all records to have distinct ids across the database
    DELETE FROM #IdTable
    DBCC CHECKIDENT('#IdTable', RESEED, @newLowId)

    --**** GENERATE COLUMN SQL (for inserts and deletes - updating identities is not allowed) ****
    DECLARE tableColumns CURSOR FOR
        SELECT column_name FROM information_schema.columns
        WHERE '[' + table_schema + '].[' + table_name + ']' = @Table
        AND column_name <> @IdColumn
    OPEN tableColumns
    DECLARE @columnName VARCHAR(100)
    DECLARE @columns VARCHAR(4000)
    SET @columns = ''
    FETCH NEXT FROM tableColumns INTO @columnName
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @columns = @columns + @columnName
        FETCH NEXT FROM tableColumns INTO @columnName
        IF @@FETCH_STATUS = 0 SET @columns = @columns + ', '
    END

    CLOSE tableColumns
    DEALLOCATE tableColumns

    --**** GENERATE FOREIGN ROW UPDATE SQL ****
    DECLARE foreignkeys SCROLL CURSOR
    FOR 
    SELECT con.name, 
        '[' + SCHEMA_NAME(f.schema_id) + '].[' + f.name + ']' fTable, fc.column_name , 
        '[' + SCHEMA_NAME(p.schema_id) + '].[' + p.name + ']' pTable,  pc.column_name 
    FROM sys.foreign_keys con
    INNER JOIN sysforeignkeys syscon
        ON con.object_id = syscon.constid
    INNER JOIN sys.objects f
        ON con.parent_object_id = f.object_id
    INNER JOIN information_schema.columns fc
        ON fc.table_schema = SCHEMA_NAME(f.schema_id)
        AND fc.table_name = f.name
        AND fc.ordinal_position = syscon.fkey

    INNER JOIN sys.objects p
        ON con.referenced_object_id = p.object_id
    INNER JOIN information_schema.columns pc
        ON pc.table_schema = SCHEMA_NAME(p.schema_id)
        AND pc.table_name = p.name
        AND pc.ordinal_position = syscon.rkey
    WHERE '[' + SCHEMA_NAME(p.schema_id) + '].[' + p.name + ']' = @Table

    OPEN foreignkeys

    DECLARE @FKeyName VARCHAR(100)
    DECLARE @FTable VARCHAR(100)
    DECLARE @FColumn VARCHAR(100)
    DECLARE @PTable VARCHAR(100)
    DECLARE @PColumn VARCHAR(100)

    --**** RE-WRITE ALL IDS IN THE TABLE ****
    SET @sql='DECLARE tablerows CURSOR FOR
    SELECT CAST('+@IdColumn+' AS VARCHAR) FROM '+@Table+' ORDER BY '+@IdColumn
    PRINT(@sql)
    exec(@sql)

    OPEN tablerows
    DECLARE @rowid VARCHAR(100)
    DECLARE @id VARCHAR(100)


    FETCH NEXT FROM tablerows INTO @rowid
    WHILE @@FETCH_STATUS = 0
    BEGIN
        --generate new id
        INSERT INTO #IdTable VALUES ('')
        SELECT @id = CAST(@@IDENTITY AS VARCHAR)
        IF @rowId <> @Id
        BEGIN
            PRINT('Modifying '+@Table+': changing '+@rowId+' to '+@id)
            SET @sql='SET IDENTITY_INSERT ' + @Table + ' ON
    INSERT INTO '+@Table+' ('+@IdColumn+','+@columns+') SELECT '+@id+','+@columns+' FROM '+@Table+' WHERE '+@IdColumn+'='+@rowId

            --Updating all foreign rows...
            FETCH FIRST FROM foreignkeys
            INTO @FKeyName, @FTable, @FColumn, @PTable, @PColumn

            WHILE @@FETCH_STATUS = 0
            BEGIN
                SET @sql = @sql + '
    UPDATE '+@FTable+' SET '+@FColumn+'='+@id+' WHERE '+@FColumn+' ='+@rowId
                FETCH NEXT FROM foreignkeys
                INTO @FKeyName, @FTable, @FColumn, @PTable, @PColumn
            END
            SET @sql=@sql + '
    DELETE FROM '+@Table+' WHERE '+@IdColumn+'='+@rowId

            PRINT(@sql)
            exec(@sql)
        END
        FETCH NEXT FROM tablerows INTO @rowid
    END

    CLOSE tablerows
    DEALLOCATE tablerows
    CLOSE foreignkeys
    DEALLOCATE foreignkeys

    --Revert to normal identity operation - update the identity to the latest id...
    DBCC CHECKIDENT(@Table, RESEED, @@IDENTITY)
    SET @sql='SET IDENTITY_INSERT ' + @Table + ' OFF'
    PRINT(@sql)
    exec(@sql)

    FETCH NEXT FROM tables
    INTO @Table, @IdColumn
END

CLOSE tables
DEALLOCATE tables

DROP TABLE #IdTable
--COMMIT
--ROLLBACK

可以,但这将涉及修改代码,而不是使用标识。保存客户端和配置的代码是相同的,而当前数据存在问题。不管我们做什么,我们都需要修改数据库,所以我们不妨走这条路。这真是太棒了——只需偏移id。我的解决方案会在所有行中移动光标并更新它们。非常烦人和缓慢,但它只有几千行…但请注意,它不会工作,因为IDENTITY_INSERT只适用于插入,而不适用于更新。更新包括一个添加和一个删除。将代码更改为使用SELECT INTO而不是UPDATE-我必须自己做这件事,但我忘记了这一点。