[这是一个不寻常的问题,我知道......]
我需要的是一个脚本,它会将每个唯一的id值更改为数据库中的新值。问题是我们有配置表可以在我们的软件实例之间导出,这些实例是id敏感的(破坏现有的id)。多年前,我们在开发“标准配置”和客户端实例之间建立了“足够广泛”的ID差距,现在不够足够宽广:(例如,当我们遇到id冲突时客户导入我们的标准配置。
执行以下操作的sql脚本绝对是我们可以做的最简单/最短时间的事情。例如修复代码太复杂,容易出错。请注意,我们并没有“消除”这里的问题。只需将差距从1000转换到1000000或更高(现有差距需要5年才能填补)。
我认为最简单的解决方案是:
是否有人为此(或部分脚本?)有任何脚本。我会赞成任何有用的东西:)。
答案 0 :(得分:1)
不幸的是,在Sql Server的世界中不存在UPDATE_CASCADE。我建议你为每个表重新键入你做以下(伪代码)
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对象自动化,但是根据所涉及的表的数量,我会说使用管理工作室来生成可以编辑的脚本可能更快。毕竟,你只需要做一次/ 5年。
答案 1 :(得分:0)
这里我们使用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
答案 2 :(得分:-1)
为什么不使用负数作为标准配置值,并继续使用正数表示其他内容?