我正在编写一个脚本,以使5个不同的列可为空(我们要确保在进行强制删除之前,系统能够完美运行)。我的存储过程可以正常工作,并且已经过测试。
但是,当我尝试整体运行此脚本时,该脚本将失败或无法使列可为空。我认为这是由于BEGIN TRY
和BEGIN TRANSACTION
导致的。似乎正在尝试在每次运行时创建存储过程?
在脚本开始时创建临时存储过程,然后运行BEGIN TRANSACTION
使这些列为空的正确方法是什么?
我应该摆脱BEGIN TRANS
并仅保留BEGIN TRY
吗?
我得到的错误是
Msg 50000,第16级,状态9,第222行
似乎有时它尝试再次创建存储过程,即使该存储过程已经存在。我应该继续将其隔离在其他脚本中吗?
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID ( '#MakeColumnsNullable', 'P' ) IS NOT NULL
DROP PROCEDURE #MakeColumnsNullable;
GO
-- create a temporary stored procedure to Drop Constraints
CREATE PROCEDURE #MakeColumnsNullable
@tableName VARCHAR(255),
@columnName VARCHAR(255)
AS
BEGIN
DECLARE @sql NVARCHAR(MAX);
DECLARE @columnType NVARCHAR(MAX);
DECLARE @constraintname SYSNAME;
DECLARE @objectid INT
BEGIN
--Make all columns that will later be deleted NULLABLE
SET @columnType = (SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_NAME = REPLACE(@tableName, 'NPI.', '')
OR TABLE_NAME = REPLACE(@tableName, 'FastTrak.', ''))
AND COLUMN_NAME = @columnName)
IF EXISTS(SELECT 1 FROM sys.columns
WHERE Name = @columnName
AND Object_ID = Object_ID(@tableName))
BEGIN
SET @sql = N'ALTER TABLE ' + @tableName + ' ALTER COLUMN ' + @columnName + ' ' + @columnType + ' NULL '
EXEC (@sql)
END
END
END
GO
BEGIN TRY
BEGIN TRANSACTION
EXEC #MakeColumnsNullable 'NPI.Table1', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'DelFlag';
EXEC #MakeColumnsNullable 'NPI.Table2', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'DelFlag';
EXEC #MakeColumnsNullable 'NPI.Table3', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'DelFlag';
COMMIT TRANSACTION;
--After COMMIT TRANSACTION drop the procedure
DROP PROCEDURE #MakeColumnsNullable;
/* Stored procedures TO BE REMOVED */
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc1')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop deprecated stored procedure OutdatedSproc1
EXEC('DROP PROCEDURE NPI.OutdatedSproc1')
PRINT ' NPI.OutdatedSproc1DROPPED'
END
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc2')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop Deprecated stored procedure OutdatedSproc2
EXEC('DROP PROCEDURE NPI.OutdatedSproc2');
PRINT ' NPI.OutdatedSproc2DROPPED';
END
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc3')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop deprecated stored procedure OutdatedSproc3
EXEC('DROP PROCEDURE NPI.OutdatedSproc3');
PRINT ' NPI.OutdatedSproc3DROPPED';
END
END TRY
BEGIN CATCH
DECLARE @Error INT = @@ERROR;
ROLLBACK TRANSACTION;
DECLARE @ErrorMessage nvarchar(4000) =
'Error in ' + OBJECT_NAME(@@PROCID) + ': ' + ERROR_MESSAGE();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
PRINT @ErrorMessage;
PRINT @ErrorSeverity;
PRINT @ErrorState;
END CATCH
答案 0 :(得分:0)
我的建议基本上是,在全局级别上创建存储过程(临时)并使用单独的脚本,其他问题:
- 在脚本开始时创建临时存储过程然后运行BEGIN TRANSACTION使这些列可为空的正确方法是什么?
答案:与顺序无关(我认为应该在单独的脚本中创建并使用全局临时存储过程),如果您决定保留TRANSACTION是因为您正在寻找根据您的经验,更改中的原子性是唯一的,我只关心表的大小以及是否需要阻塞和消耗许多资源。
- 我应该摆脱BEGIN TRANS并仅保留BEGIN TRY吗?
答案:您是否需要原子性作为此更改的一部分,如果答案是否定的,您只能保留BEGIN TRY。
答案 1 :(得分:0)
谢谢大家的反馈,我意识到有些错误的地方:
谢谢大家的帮助,希望这对以后的人有所帮助。
正确的存储过程:
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID('tempdb..#MakeColumnsNullable') IS NOT NULL
BEGIN
DROP PROC #MakeColumnsNullable
END
GO
-- create a temporary stored procedure to Drop Constraints
CREATE PROCEDURE #MakeColumnsNullable
@tableName varchar(255),
@columnName varchar(255)
AS
BEGIN
DECLARE @sql NVARCHAR(MAX);
DECLARE @columnType NVARCHAR(MAX);
DECLARE @constraintname SYSNAME;
DECLARE @dropIndexStatement NVARCHAR(MAX);
DECLARE @createIndexStatement NVARCHAR(MAX);
DECLARE @indexName NVARCHAR(MAX);
DECLARE @objectid int
BEGIN
--Get column type
SET @columnType = (SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (TABLE_NAME = REPLACE(@tableName, 'NPI.', '') OR TABLE_NAME = REPLACE(@tableName, 'FastTrak.', ''))
AND COLUMN_NAME = @columnName)
-- need to see if there are any references to indexes
IF EXISTS(SELECT name FROM sys.indexes WHERE object_id = object_id(@tableName) AND filter_definition like '%'+ @columnName +'%' AND type_desc = 'NONCLUSTERED')
BEGIN
set @indexName = (SELECT name FROM sys.indexes WHERE object_id = object_id(@tableName) AND filter_definition like '%'+ @columnName +'%' AND type_desc = 'NONCLUSTERED');
set @dropIndexStatement = N'DROP INDEX ' + @indexName + ' ON ' + @tableName + ' '
set @createIndexStatement = N'CREATE INDEX ' + @indexName + ' ON ' + @tableName + ' (' + @columnName + ') '
--PRINT @dropIndexStatement;
EXEC (@dropIndexStatement)
END
-- Make the column nullable
IF EXISTS(SELECT 1 FROM sys.columns
WHERE Name = @columnName
AND Object_ID = Object_ID(@tableName))
BEGIN
set @sql = N'alter table ' + @tableName + ' ALTER COLUMN ' + @columnName + ' ' + @columnType + ' NULL '
--PRINT @sql;
EXEC (@sql)
END
--RECREATE INDEX IF @createIndexStatement has been SET
IF (@createIndexStatement IS NOT NULL) OR (LEN(@createIndexStatement) > 0)
BEGIN
--PRINT @createIndexStatement;
EXEC (@createIndexStatement)
END
END
END
GO
BEGIN TRY
BEGIN TRANSACTION
EXEC #MakeColumnsNullable 'NPI.Table1', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table1', 'DelFlag';
EXEC #MakeColumnsNullable 'NPI.Table2', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table2', 'DelFlag';
EXEC #MakeColumnsNullable 'NPI.Table3', 'CreateID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'CreateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'UpdateID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'UpdateComponentID';
EXEC #MakeColumnsNullable 'NPI.Table3', 'DelFlag';
/* SPROCS TO BE REMOVED */
IF OBJECT_ID('tempdb..#MakeColumnsNullable') IS NOT NULL
BEGIN
DROP PROC #MakeColumnsNullable
END
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc1')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop deprecated stored procedure OutdatedSproc1
EXEC('DROP PROCEDURE NPI.OutdatedSproc1')
PRINT ' NPI.OutdatedSproc1DROPPED'
END
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc2')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop Deprecated stored procedure OutdatedSproc2
EXEC('DROP PROCEDURE NPI.OutdatedSproc2');
PRINT ' NPI.OutdatedSproc2DROPPED';
END
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'NPI.OutdatedSproc3')
AND type IN (N'P', N'PC'))
BEGIN
-- Drop deprecated stored procedure OutdatedSproc3
EXEC('DROP PROCEDURE NPI.OutdatedSproc3');
PRINT ' NPI.OutdatedSproc3DROPPED';
END
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
PRINT 'TRAN ROLLEDBACK FOR SOME REASON';
ROLLBACK TRANSACTION
END
DECLARE @ErrorMessage nvarchar(4000) = 'Error is ' + ltrim(str(@@ERROR)) + '.';
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
PRINT @ErrorMessage;
PRINT @ErrorSeverity;
PRINT @ErrorState;
THROW;
END CATCH