我创建了一个存储过程 (
proc_dropUser
) 来循环遍历所有数据库并删除用户。
但是很多时候当用户拥有架构时我会遇到错误 15138。
因此,我创建了另一个过程(
proc_altAuthorization
)来更改数据库用户拥有的模式的授权。
我想做的是,每当我在执行
proc_dropUser
时遇到特定错误时,就执行proc_altAuthorization
,然后返回到第一个程序并继续。
类似:
CREATE proc_dropUser
@userName
--Cursor to DROP USER from each @dbName
IF ERROR_NUMBER() = 15138
EXEC proc_altAuthorization @userName, @dbName
FETCH NEXT FROM cursor INTO @user
GO
并且
proc_altAuthorization
将接受参数并更改授权。
CREATE proc_altAuthorization
@userName, @dbName
--build dynamic sql query
SET @dsql = N'USE ' + @dbName + N'
ALTER AUTHORIZATION ON SCHEMA:: '+@schema + ' TO dbo'
EXEC(@dsql)
RETURN --not sure!
我想可以使用 TRY CATCH 块,但不知道如何使用。
我已经有一段时间找到问题的解决方案了,但意识到我从未将其发布在这里。这是我找到的解决方案。它实现了我在问题中提到的 TRY-CATCH 相同逻辑,但不具备如何实现的技术知识。
CREATE PROCEDURE proc_dropUser
@userName NVARCHAR(128)
AS
BEGIN
DECLARE @dbName NVARCHAR(128)
DECLARE @sql NVARCHAR(MAX)
DECLARE @schema NVARCHAR(128)
-- Declare a cursor for iterating through all databases
DECLARE db_cursor CURSOR FOR
SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @dbName
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
-- Build the dynamic SQL to drop the user from each database
SET @sql = N'USE ' + QUOTENAME(@dbName) + N';
IF EXISTS (SELECT * FROM sys.database_principals WHERE name = @userName)
BEGIN
DROP USER ' + QUOTENAME(@userName) + N';
END'
EXEC proc_executesql @sql, N'@userName NVARCHAR(128)', @userName
END TRY
BEGIN CATCH
-- Check if the error is 15138 (user owns a schema)
IF ERROR_NUMBER() = 15138
BEGIN
-- Execute proc_altAuthorization to alter the schema ownership
EXEC proc_altAuthorization @userName, @dbName
-- Retry dropping the user after the schema ownership is changed
SET @sql = N'USE ' + QUOTENAME(@dbName) + N';
DROP USER ' + QUOTENAME(@userName) + N';'
EXEC proc_executesql @sql
END
END CATCH
-- Fetch the next database
FETCH NEXT FROM db_cursor INTO @dbName
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
希望这可以帮助遇到类似需求的其他人。干杯!