Мы просматриваем нашу базу данных (SQL Server 2014) и проводим некоторую нормализацию. База данных была перенесена из MS Access постепенно в течение многих лет многими разными людьми, и, к сожалению, столбцы не являются стандартными для всех таблиц. Я создал скрипт ниже, пытаясь сделать это автоматически, потому что есть много таблиц. Я продолжаю бить стену за стеной. Последняя стена, которую я пробиваю и с трудом преодолеваю, это: Несколько замечаний по поводу этого скрипта:
В нем содержится таблица ColumnModel, которая содержит имя столбца и тип данных, в который мы хотим преобразовать столбец.
До сих пор я запускал два других сценария для базы данных, пытаясь заставить это работать. Первый скрипт снял все ограничения. Второй сценарий должен был удалить все индексы из всех таблиц, но я продолжаю сталкиваться с ошибкой, изображенной выше.
DECLARE @Tables TABLE (TableName VARCHAR(200))
DECLARE @Columns TABLE (ColumnName VARCHAR(200))
DECLARE @TableName AS VARCHAR(200)
DECLARE @ColumnName AS VARCHAR(200)
DECLARE @NewDataType AS VARCHAR(200)
DECLARE @SQL AS VARCHAR(500)
DECLARE @Nullable AS BIT
INSERT INTO @Tables
SELECT DISTINCT o.name AS TableName FROM sys.columns c
INNER JOIN sys.objects o on c.object_id=o.object_id
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
INNER JOIN ColumnModel cm ON '['+ c.name+ ']' = cm.[Column]
ORDER BY o.name
SELECT @TableName= MIN(TableName) FROM @Tables
WHILE @TableName IS NOT NULL
BEGIN
INSERT INTO @Columns
SELECT c.name AS ColumnName FROM sys.columns c
INNER JOIN sys.objects o on c.object_id=o.object_id
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
INNER JOIN ColumnModel cm ON '['+ c.name+ ']' = cm.[Column]
WHERE o.name = @TableName
ORDER BY c.name
-- LOOP THROUGH EACH COLUMN IN TABLE AND MODIFY DATATYPE
SELECT @ColumnName= MIN(ColumnName) FROM @Columns
WHILE @ColumnName IS NOT NULL
BEGIN
-- DETERMINE IF Column Is Nullable or not
SET @Nullable = (SELECT c.is_nullable FROM sys.columns c
INNER JOIN sys.objects o on c.object_id=o.object_id
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
INNER JOIN ColumnModel cm ON '['+ c.name+ ']' = cm.[Column]
WHERE o.name = @TableName AND c.name = @ColumnName)
-- GET New Data Type
SET @NewDataType = (SELECT DataType FROM ColumnModel WHERE [Column] = '['+ @ColumnName+ ']')
IF @Nullable = 1
BEGIN
SET @SQL = 'ALTER TABLE dbo.[' + @TableName + '] ALTER COLUMN [' + @ColumnName + '] ' + @NewDataType + ' NULL'
EXEC(@SQL)
PRINT @SQL
END
IF @Nullable = 0
BEGIN
-- ALTER COLUMN
SET @SQL = 'ALTER TABLE dbo.[' + @TableName + '] ALTER COLUMN [' + @ColumnName + '] ' + @NewDataType + ' NOT NULL'
EXEC(@SQL)
PRINT @SQL
END
DELETE FROM @Columns
-- MOVE NEXT COLUMN
SELECT @ColumnName = MIN(ColumnName) FROM @Columns WHERE ColumnName > @ColumnName
END
-- MOVE NEXT TABLE
SELECT @TableName = MIN(TableName) FROM @Tables WHERE TableName > @TableName
END
УДАЛИТЬ ВСЕ индексы БД Скрипт:
SELECT 'ALTER INDEX ' + QUOTENAME(I.name) + ' ON ' + QUOTENAME(SCHEMA_NAME(T.schema_id))+'.'+ QUOTENAME(T.name) + ' DISABLE'
FROM sys.indexes I
INNER JOIN sys.tables T ON I.object_id = T.object_id
WHERE I.type_desc = 'NONCLUSTERED'
AND I.name IS NOT NULL
AND I.is_disabled = 0
Сценарий удаления и создания всех ограничений, которые я здесь записал: https://www.mssqltips.com/sqlservertip/3347/drop-and-recreate-all-foreign-key-constraints-in-sql-server/
Единственное изменение, которое я создал локальный таблица вместо табличной переменной. Однако этот сценарий сгенерировал весь код удаления в одном столбце и весь код создания в другом столбце ... вместо добавления его в строки. Как вы думаете, возможно, что столбцы не могут содержать полный сценарий? Столбец, похоже, не был усечен, поэтому я подумал, что это не проблема.
В обоих этих сценариях я скопировал динамически созданный код и выполнил его вручную.