我必须更改大量表格30+一列的数据类型从fgets
到Int
。
我的问题是,特定列也适用于BigInt
的一个表,而其他许多列PK
。因此,当我收到错误消息时,我无法更改。
我需要一个算法或一些脚本。但我无法弄清楚步骤或方法:我应该使用光标,还是只使用临时表来删除记录并始终获取第一个...
我该怎么办?从堆栈中取出第一个表,检查所讨论的列是由PK还是FK引用,如果是这样,删除引用(PK,FK等)然后改变列类型,然后重新创建Pk和FK?我应该存储我掺杂的东西吗?我很困惑......
任何提示?
答案 0 :(得分:3)
如果您有很多内容,一种选择是不删除记录,而是考虑为每个BigInt数据类型的表添加另一列,然后将数据从主键列移动到此新列。
ALTER TABLE Table1 ADD COLUMN NewPKColumn BigInt;
UPDATE Table1 SET NewPkColumn = CurrentPKColumn;
您对引用此新BigInt列的其他表执行相同操作,添加数据类型BigInt的新列,移动数据。
ALTER TABLE Table2 ADD COLUMN NewPKColumn_FK BigInt;
UPDATE Table2 SET NewPKColumn_FK = Current_FK_Column;
(repeat this for all tables...)
当您为所有表执行此操作后,您可以从原始PK列中删除PK并删除该列(但在此之前,请务必查看并查看创建的索引类型在PK栏上 - 群集或非群集)并且不要忘记再次创建FK。
ALTER TABLE Table2 DROP CONSTRAINT FK_Tbl1;
ALTER TABLE Table1 DROP COLUMN CurrentPKColumn;
ALTER TABLE Table2 ADD CONSTRAINT FK_Tbl1 REFERENCES Table1(NewPKColumn);
此外,您需要查看存在哪些索引并包含当前的PK列,因为您还需要重新创建这些索引。
而且,与往常一样,首先在开发环境中对此进行测试,以确保您没有跳过任何内容。
答案 1 :(得分:2)
好的,这将是一个脚本的野兽,但我现在正在解决同样的问题。此脚本仍在进行中,但应该可以帮助您完成您需要做的事情。
我当前的代码使用给定的表格和字段,随时可以编辑;
DECLARE @TableToEdit varchar(255); SET @TableToEdit = 'Entity'
DECLARE @MasterField sysname; SET @MasterField = 'Entity_Identifier'
您需要先删除所有外键;
IF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL
DROP TABLE #ForeignKeys
CREATE TABLE #ForeignKeys
(
PKTABLE_QUALIFIER nvarchar(255) NULL
,PKTABLE_OWNER nvarchar(255) NULL
,PKTABLE_NAME nvarchar(255) NULL
,PKCOLUMN_NAME varchar(255) NULL
,FKTABLE_QUALIFIER nvarchar(255) NULL
,FKTABLE_OWNER nvarchar(255) NULL
,FKTABLE_NAME nvarchar(255) NULL
,FKCOLUMN_NAME nvarchar(255) NULL
,KEY_SQL int NULL
,UPDATE_RULE int NULL
,DELETE_RULE int NULL
,FK_NAME nvarchar(255) NULL
,PK_NAME nvarchar(255) NULL
,DEFERRABILITY int NULL
)
/* find all tables that have an Entity_Identifier field that's not already an int */
IF OBJECT_ID('tempdb..#MasterTables') IS NOT NULL DROP TABLE #MasterTables
CREATE TABLE #MasterTables (MasterTableName sysname, MasterTableSQL nvarchar(max))
INSERT INTO #MasterTables (MasterTableName, MasterTableSQL)
SELECT DISTINCT
o.name TableName
,'INSERT INTO #ForeignKeys EXEC sp_fkeys ' + o.name MasterTableSQL
FROM sys.objects o
JOIN sys.columns c
ON o.object_id = c.object_id
JOIN sys.types t
ON c.user_type_id = t.user_type_id
WHERE o.type = 'u'
--AND t.name NOT IN ('int','bigint')
--AND c.name LIKE '%Entity_Identifier%'
AND c.name LIKE '%' + @MasterField + '%'
/* Let's find all Foreign Keys based upon a table that has an Entity_Identifier field that needs to be converted */
DECLARE @execspfkeys nvarchar(max)
DECLARE spfkeyscursor CURSOR LOCAL FOR
SELECT MasterTableSQL FROM #MasterTables
OPEN spfkeyscursor
FETCH NEXT FROM spfkeyscursor INTO @execspfkeys
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @execspfkeys
FETCH NEXT FROM spfkeyscursor INTO @execspfkeys
END
CLOSE spfkeyscursor
DEALLOCATE spfkeyscursor
/* Ok, let's get the foreign key definitions from all relevant tables */
IF OBJECT_ID('tempdb..#FKScripts') IS NOT NULL
DROP TABLE #FKScripts
CREATE TABLE #FKScripts
(
FKName nvarchar(255)
,FKTableName nvarchar(255)
,FKSchema nvarchar(10)
,FKDatabase nvarchar(255)
,PKName nvarchar(255)
,PKTableName nvarchar(255)
,PKSchema nvarchar(10)
,PKDatabase nvarchar(255)
,FKDisableScript nvarchar(max)
,FKRebuildScript nvarchar(max)
,FKCheckScript nvarchar(max)
)
INSERT INTO #FKScripts (FKName, FKTableName, FKSchema, FKDatabase, PKName, PKTableName, PKSchema, PKDatabase, FKDisableScript, FKRebuildScript, FKCheckScript)
SELECT DISTINCT
fk.FK_NAME
,fk.FKTABLE_NAME
,fk.FKTABLE_OWNER
,fk.FKTABLE_QUALIFIER
,fk.PK_NAME
,fk.PKTABLE_NAME
,fk.PKTABLE_OWNER
,fk.PKTABLE_QUALIFIER
,'ALTER TABLE [' + fk.FKTABLE_OWNER + '].[' + fk.FKTABLE_NAME + '] DROP CONSTRAINT [' + fk.FK_NAME + ']' FKDisableScript
,'ALTER TABLE [' + fk.FKTABLE_OWNER + '].[' + fk.FKTABLE_NAME + '] WITH CHECK ADD CONSTRAINT [' + fk.FK_NAME + '] FOREIGN KEY (' + PKList.FieldList +') REFERENCES [dbo].[' + fk.PKTABLE_NAME + '] (' + FKlist.FieldList + ')' FKRebuildScript
,'ALTER TABLE [' + fk.FKTABLE_OWNER + '].[' + fk.FKTABLE_NAME + '] CHECK CONSTRAINT [' + fk.FK_NAME + ']' FKCheckScript
FROM #ForeignKeys fk
INNER JOIN
(
SELECT DISTINCT
fk.FK_NAME,
STUFF((SELECT ','+ fk2.PKCOLUMN_NAME
FROM (SELECT FK_NAME, '[' + PKCOLUMN_NAME +']' PKCOLUMN_NAME FROM #ForeignKeys) fk2
WHERE FK.FK_NAME = fk2.FK_NAME
GROUP BY fk2.PKCOLUMN_NAME
FOR XML PATH(''), TYPE).value('.','VARCHAR(max)'), 1, 1, '') FieldList
FROM #ForeignKeys fk
) PKlist
ON fk.FK_NAME = PKlist.FK_NAME
INNER JOIN
(
SELECT DISTINCT
fk.FK_NAME,
STUFF((SELECT ','+ fk2.FKCOLUMN_NAME
FROM (SELECT FK_NAME, '[' + FKCOLUMN_NAME + ']' FKCOLUMN_NAME FROM #ForeignKeys) fk2
WHERE FK.FK_NAME = fk2.FK_NAME
GROUP BY fk2.FKCOLUMN_NAME
FOR XML PATH(''), TYPE).value('.','VARCHAR(max)'), 1, 1, '') FieldList
FROM #ForeignKeys fk
) FKlist
ON fk.FK_NAME = FKlist.FK_NAME
DROP TABLE #ForeignKeys
SELECT * FROM #FKScripts
/* OK, let's disable these foreign keys, going to have to use a cursor for this (ouch) */
DECLARE @disablesql nvarchar(max)
DECLARE discur CURSOR LOCAL FOR
SELECT FKDisableScript FROM #FKScripts
OPEN discur
FETCH NEXT FROM discur INTO @disablesql
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @disablesql
FETCH NEXT FROM discur INTO @disablesql
END
CLOSE discur
DEALLOCATE discur
/* right, we're finished with the cursor that disables the foreign keys, phew! */
/* check that the constraints are now disabled (for testing) */
SELECT DISTINCT
fkt.*
,CASE WHEN ((C.Status & 0x4000)) = 0 THEN 1 ELSE 0 END [Enabled2]
FROM #FKScripts fkt
INNER JOIN sys.sysobjects o2
ON o2.name = fkt.FKName
INNER JOIN sys.sysobjects o
ON o2.id = o.parent_obj
AND o.xtype='F'
INNER JOIN sys.sysconstraints c
ON o.id = c.constid
select * from #FKScripts
然后你需要删除所有索引;
/* Drop index scripts into a temp table */
IF OBJECT_ID('tempdb..#CreateIndexes') IS NOT NULL DROP TABLE #CreateIndexes
GO
DECLARE @SchemaName varchar(100)
DECLARE @TableName varchar(256)
DECLARE @IndexName varchar(256)
DECLARE @ColumnName varchar(100)
DECLARE @is_unique varchar(100)
DECLARE @IndexTypeDesc varchar(100)
DECLARE @FileGroupName varchar(100)
DECLARE @is_disabled bit
DECLARE @is_primary_key bit
DECLARE @IndexOptions varchar(max)
DECLARE @IndexColumnId int
DECLARE @IsDescendingKey int
DECLARE @IsIncludedColumn int
DECLARE @TSQLScripCreationIndex varchar(max)
DECLARE @TSQLScripDisableIndex varchar(max)
CREATE TABLE #CreateIndexes (
SchemaName varchar(max)
,TableName varchar(max)
,IndexName varchar(max)
,is_unique varchar(max)
,IndexTypeDesc varchar(max)
,is_disabled bit
,is_primary_key bit
,FileGroupName varchar(max)
,DropScript varchar(max)
,TSQLScripCreationIndex varchar(max)
,TSQLScripDisableIndex varchar(max)
)
DECLARE CursorIndex CURSOR FOR
SELECT schema_name(t.schema_id) [schema_name]
, t.name
, ix.name
, CASE WHEN ix.is_unique = 1 THEN 'UNIQUE ' ELSE '' END
, ix.type_desc
, '' IndexOptions -- case when ix.is_padded=1 then 'PAD_INDEX = ON, ' else 'PAD_INDEX = OFF, ' end
--+ case when ix.allow_page_locks=1 then 'ALLOW_PAGE_LOCKS = ON, ' else 'ALLOW_PAGE_LOCKS = OFF, ' end
--+ case when ix.allow_row_locks=1 then 'ALLOW_ROW_LOCKS = ON, ' else 'ALLOW_ROW_LOCKS = OFF, ' end
--+ case when INDEXPROPERTY(t.object_id, ix.name, 'IsStatistics') = 1 then 'STATISTICS_NORECOMPUTE = ON, ' else 'STATISTICS_NORECOMPUTE = OFF, ' end
--+ case when ix.ignore_dup_key=1 then 'IGNORE_DUP_KEY = ON, ' else 'IGNORE_DUP_KEY = OFF, ' end
--+ 'SORT_IN_TEMPDB = OFF, FILLFACTOR = ' + CASE WHEN ix.fill_factor = 0 THEN '90' ELSE CAST(ix.fill_factor AS VARCHAR(3)) END AS IndexOptions
, ix.is_disabled
, ix.is_primary_key
, FILEGROUP_NAME(ix.data_space_id) FileGroupName
FROM sys.tables t
INNER JOIN sys.indexes ix on t.object_id=ix.object_id
INNER JOIN #FKScripts fks ON t.name = fks.FKTableName
WHERE ix.type>0
AND t.is_ms_shipped=0
AND t.name<>'sysdiagrams'
--and t.name = 'Entity'
ORDER BY schema_name(t.schema_id), t.name, ix.name
OPEN CursorIndex
FETCH NEXT FROM CursorIndex INTO @SchemaName, @TableName, @IndexName, @is_unique, @IndexTypeDesc, @IndexOptions,@is_disabled, @is_primary_key, @FileGroupName
WHILE (@@fetch_status=0)
BEGIN
DECLARE @IndexColumns varchar(max)
DECLARE @IncludedColumns varchar(max)
SET @IndexColumns=''
SET @IncludedColumns=''
DECLARE CursorIndexColumn CURSOR FOR
SELECT
col.name
,ixc.is_descending_key
,ixc.is_included_column
FROM sys.tables tb
INNER JOIN sys.indexes ix
ON tb.object_id=ix.object_id
INNER JOIN sys.index_columns ixc
ON ix.object_id=ixc.object_id
AND ix.index_id= ixc.index_id
INNER JOIN sys.columns col
ON ixc.object_id = col.object_id
AND ixc.column_id = col.column_id
WHERE ix.type>0
AND (ix.is_primary_key=0 or ix.is_unique_constraint=0)
AND schema_name(tb.schema_id) = @SchemaName
AND tb.name = @TableName
AND ix.name = @IndexName
ORDER BY ixc.index_column_id
OPEN CursorIndexColumn
FETCH NEXT FROM CursorIndexColumn INTO @ColumnName, @IsDescendingKey, @IsIncludedColumn
WHILE (@@fetch_status=0)
BEGIN
IF @IsIncludedColumn=0
SET @IndexColumns=@IndexColumns + @ColumnName + CASE WHEN @IsDescendingKey=1 THEN ' DESC, ' ELSE ' ASC, ' END
ELSE
SET @IncludedColumns=@IncludedColumns + @ColumnName +', '
FETCH NEXT FROM CursorIndexColumn INTO @ColumnName, @IsDescendingKey, @IsIncludedColumn
END
CLOSE CursorIndexColumn
DEALLOCATE CursorIndexColumn
SET @IndexColumns = substring(@IndexColumns, 1, len(@IndexColumns)-1)
SET @IncludedColumns = CASE WHEN len(@IncludedColumns) >0 THEN substring(@IncludedColumns, 1, len(@IncludedColumns)-1) ELSE '' END
-- print @IndexColumns
-- print @IncludedColumns
SET @TSQLScripCreationIndex =''
SET @TSQLScripDisableIndex =''
SET @TSQLScripCreationIndex=
CASE WHEN @is_primary_key = 1 THEN 'ALTER TABLE ' + QUOTENAME(@SchemaName) +'.'+ QUOTENAME(@TableName) + ' ADD CONSTRAINT ' + QUOTENAME(@IndexName) + ' PRIMARY KEY CLUSTERED (' + @IndexColumns + ' )' + @IndexOptions + ' ON ' + QUOTENAME(@FileGroupName) + ';'
ELSE 'CREATE '+ @is_unique +@IndexTypeDesc + ' INDEX ' +QUOTENAME(@IndexName)+' ON ' + QUOTENAME(@SchemaName) +'.'+ QUOTENAME(@TableName)+ ' ('+@IndexColumns+') '
+ CASE WHEN len(@IncludedColumns)>0 THEN 'INCLUDE (' + @IncludedColumns+ ')' ELSE '' END + CHAR(13) --+'WITH (' + @IndexOptions+ ') ON ' + QUOTENAME(@FileGroupName) + ';'
END
--if @is_disabled=1
SET @TSQLScripDisableIndex= CASE WHEN @IndexTypeDesc = 'CLUSTERED' THEN 'ALTER TABLE ' + QUOTENAME(@SchemaName) +'.'+ QUOTENAME(@TableName) + ' DROP CONSTRAINT ' + QUOTENAME(@IndexName)
ELSE 'DROP INDEX ' + QUOTENAME(@IndexName) + ' ON ' + QUOTENAME(@SchemaName) +'.'+ QUOTENAME(@TableName) + CHAR(13) END
PRINT @TSQLScripCreationIndex
PRINT @TSQLScripDisableIndex
INSERT INTO #CreateIndexes (SchemaName, TableName, IndexName, is_unique, IndexTypeDesc, is_disabled, is_primary_key ,FileGroupName, TSQLScripCreationIndex, TSQLScripDisableIndex)
SELECT @SchemaName, @TableName, @IndexName, @is_unique, @IndexTypeDesc, @is_disabled, @is_primary_key, @FileGroupName, @TSQLScripCreationIndex, @TSQLScripDisableIndex
FETCH NEXT FROM CursorIndex INTO @SchemaName, @TableName, @IndexName, @is_unique, @IndexTypeDesc, @IndexOptions,@is_disabled, @is_primary_key ,@FileGroupName
END
CLOSE CursorIndex
DEALLOCATE CursorIndex
SELECT * FROM #CreateIndexes ORDER BY TableName, IndexName
如果你有全文索引,那么你需要这个;
/* NEED TO DISABLE FULL TEXT INDEXES ON ANY OF THESE TABLES - AAARRRGGGGGHHHHHH!!!! */
IF OBJECT_ID('tempdb..#FullTextCreateScripts') IS NOT NULL DROP TABLE #FullTextCreateScripts
CREATE TABLE #FullTextCreateScripts (TableName sysname, ColumnName sysname, FullTextCreateScript nvarchar(max))
INSERT INTO #FullTextCreateScripts (TableName, ColumnName, FullTextCreateScript)
SELECT
o.name TableName
,c.name ColumnName
,'ADD FULLTEXT INDEX ON ' + o.name + 'ADD (' + c.name + ')' FullTextCreateScript
FROM sys.fulltext_index_columns fic
LEFT JOIN sys.objects o
ON o.object_id = fic.object_id
LEFT JOIN sys.columns c
ON c.object_id = fic.object_id
AND c.column_id = fic.column_id
INNER JOIN #FKScripts fks
ON o.name = fks.FKTableName
SELECT * FROM #FullTextCreateScripts
IF OBJECT_ID('tempdb..#FullTextDropScripts') IS NOT NULL DROP TABLE #FullTextDropScripts
CREATE TABLE #FullTextDropScripts (TableName sysname, FullTextDropScript nvarchar(max))
INSERT INTO #FullTextDropScripts (TableName, FullTextDropScript)
SELECT DISTINCT
o.name TableName
,'DROP FULLTEXT INDEX ON ' + o.name FullTextDropScript
FROM sys.fulltext_index_columns fic
LEFT JOIN sys.objects o
ON o.object_id = fic.object_id
INNER JOIN #FKScripts fks
ON o.name = fks.FKTableName
SELECT * FROM #FullTextDropScripts
/* Another cursor, this one drops our relevant full text indexes */
DECLARE @dropfulltextSQL nvarchar(max)
DECLARE dropfulltextcursor CURSOR LOCAL FOR
SELECT FullTextDropScript FROM #FullTextDropScripts
OPEN dropfulltextcursor
FETCH NEXT FROM dropfulltextcursor INTO @dropfulltextSQL
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @dropfulltextSQL
FETCH NEXT FROM dropfulltextcursor INTO @dropfulltextSQL
END
CLOSE dropfulltextcursor
DEALLOCATE dropfulltextcursor
/ *让我们使用游标* /
删除这些索引DECLARE @dropindexes nvarchar(max)
DECLARE dropindex CURSOR LOCAL FOR
SELECT TSQLScripDisableIndex FROM #CreateIndexes
OPEN dropindex
FETCH NEXT FROM dropindex INTO @dropindexes
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @dropindexes
FETCH NEXT FROM dropindex INTO @dropindexes
END
CLOSE dropindex
DEALLOCATE dropindex
这就是你想要你的ALTER SCRIPT的地方
一旦你完成了改变,然后开始重新应用你已经丢弃的所有内容;
/ *让我们将这些全文索引添加回* /
DECLARE @addfulltextSQL nvarchar(max)
DECLARE createfulltextcursor CURSOR LOCAL FOR
SELECT FullTextCreateScript FROM #FullTextCreateScripts
OPEN createfulltextcursor
FETCH NEXT FROM createfulltextcursor INTO @addfulltextSQL
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @addfulltextSQL
FETCH NEXT FROM createfulltextcursor INTO @addfulltextSQL
END
CLOSE createfulltextcursor
DEALLOCATE createfulltextcursor
/* Rebuild those indexes */
DECLARE @createindexes nvarchar(max)
DECLARE createindexes CURSOR LOCAL FOR
SELECT TSQLScripCreationIndex FROM #CreateIndexes
OPEN createindexes
FETCH NEXT FROM createindexes INTO @createindexes
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @createindexes
FETCH NEXT FROM createindexes INTO @createindexes
END
CLOSE createindexes
DEALLOCATE createindexes
/* Now let's re-enable those FK constraints */
DECLARE @enablesql nvarchar(max)
DECLARE @checksql nvarchar(max)
DECLARE enacur CURSOR LOCAL FOR
SELECT FKRebuildScript, FKCheckScript FROM #FKScripts
OPEN enacur
FETCH NEXT FROM enacur INTO @enablesql, @checksql
WHILE @@FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
EXEC sp_executesql @enablesql
EXEC sp_executesql @checksql
FETCH NEXT FROM enacur INTO @enablesql, @checkSQL
END
CLOSE enacur
DEALLOCATE enacur
/* Let's check that the constraints are now enabled again (for testing) */
SELECT DISTINCT
fkt.*
,CASE WHEN ((C.Status & 0x4000)) = 0 THEN 1 ELSE 0 END [Enabled3]
FROM #FKScripts fkt
INNER JOIN sys.sysobjects o2
ON o2.name = fkt.PKName
INNER JOIN sys.sysobjects o
ON o2.id = o.parent_obj
AND o.xtype='F'
INNER JOIN sys.sysconstraints c
ON o.id = c.constid