一部のstored procedures
を別のデータベースに移動する必要があるという問題があります。これらのSPs
は、同じデータベースと他のデータベースからも実行されます。
特にtriggers
の中から実行されます。
以下のスクリプトでは、現在のデータベースからapplicationCommission
というstored procedure
を実行するすべてのトリガーを特定できます。
私が失敗して達成したいのは:
現在のサーバーのstored procedure
を呼び出すすべてのデータベースでtriggers
をすべて検索したい。
これを実現するために、以下のスクリプトでどのような変更を行うことができますか?または
どうすればこれを達成できますか?
--============================================================================
-- the trigger definition query
-- marcelo miorelli
-- 20-july-2017
--=============================================================================
--SELECT
-- QUOTENAME(SCHEMA_NAME(schema_id)) AS schema_name,
-- QUOTENAME(OBJECT_NAME(parent_object_id)) AS table_name,
-- QUOTENAME(so.name) AS trigger_name,
-- OBJECT_DEFINITION(object_id) AS trigger_definition
--FROM sys.objects so
--WHERE so.type = 'TR'
--===============================================================================
-- find what triggers run a stored procedure
-- marcelo miorelli
-- 20-july-2017
--===============================================================================
SET NOCOUNT ON
SET DEADLOCK_PRIORITY LOW
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE @SQL NVARCHAR(max)
-- THE PROCEDURE THAT I AM LOOKING FOR
,@spName VARCHAR(100) = 'applicationCommission'
SELECT @SQL = STUFF((
SELECT CHAR(10) + ' UNION ALL ' + CHAR(10) +
' SELECT ' + quotename(s.NAME, '''') + ' AS DB_NAME ' + CHAR(10) +
' ,QUOTENAME(OBJECT_SCHEMA_NAME(so.schema_id,db_id()))
AS THE_SCHEMA ' + CHAR(10) +
' ,QUOTENAME(OBJECT_NAME(parent_object_id,db_id()))
AS table_name' + CHAR(10) +
' , so.name COLLATE Latin1_General_CI_AS
AS TRIGGER_NAME ' + CHAR(10) +
' ,OBJECT_DEFINITION(object_id)
AS trigger_definition' + CHAR(10) +
' FROM ' + quotename(s.NAME) + '.sys.objects so ' + CHAR(10) +
' WHERE 1=1 ' + CHAR(10) +
--' AND s.name LIKE @spName ' + CHAR(10) +
' AND so.[type] = ''TR'''
FROM sys.databases s
WHERE 1=1
AND S.state = 0
AND s.name NOT IN ('master', 'model',
'msdb', 'tempdb', 'distribution')
ORDER BY s.NAME
FOR XML PATH('')
,TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 11, '')
--PRINT @SQL
IF OBJECT_ID('tempdb..#Radhe') IS NOT NULL
BEGIN
DROP TABLE #RADHE
END
CREATE TABLE #Radhe(
[database_name] sysname NOT NULL,
[schema_name] sysname NULL,
[table_name] sysname NULL,
[trigger_name] sysname NOT NULL,
[trigger_definition] NVARCHAR(MAX)
);
INSERT INTO #Radhe
EXECUTE sp_executeSQL @SQL
--,N'@spName varchar(100)'
--,@spName
SELECT *
FROM #Radhe
WHERE trigger_definition LIKE '%' + @spName + '%'
編集:
これが私がこの事件を終わらせた方法です:
--==============================================================================================
-- version using cursor
-- in all databases - get all triggers that fire a particular stored procedure (accept wildcards %)
-- marcelo miorelli
-- 27-july-2017
-- https://stackoverflow.com/questions/1409965/t-sql-a-proper-way-to-close-deallocate-cursor-in-the-update-trigger
-- https://stackoverflow.com/questions/21225324/open-and-close-cursors-inside-or-outside-a-transaction-and-how-to-close-a-cursor
--==============================================================================================
USE master;
GO
IF OBJECT_ID('tempdb..#Radhe') IS NOT NULL
BEGIN
DROP TABLE #Radhe
END
CREATE TABLE #Radhe (
[DB] NVARCHAR(128) NULL,
[THE_SCHEMA] NVARCHAR(258) NULL,
[table_name] NVARCHAR(258) NULL,
[TRIGGER_NAME] NVARCHAR(128) NOT NULL,
[trigger_definition] NVARCHAR(max) NULL
)
DECLARE @name sysname;
DECLARE @SQL nvarchar(max);
DECLARE @theSQL nvarchar(max);
DECLARE @spName VARCHAR(100) = '%PropInsert%' -- THE PROCEDURE THAT I AM LOOKING FOR
SELECT @SQL =
'-------------------------------------------------------------------------------------------------------------------
SELECT
DB = DB_NAME()
,QUOTENAME(OBJECT_SCHEMA_NAME(so.schema_id,db_id())) AS THE_SCHEMA
,QUOTENAME(OBJECT_NAME(parent_object_id,db_id())) AS table_name
, so.name COLLATE Latin1_General_CI_AS AS TRIGGER_NAME
,OBJECT_DEFINITION(object_id) AS trigger_definition
FROM sys.objects so
WHERE 1=1
AND so.[type] = ''TR'' -- get only the triggers
-------------------------------------------------------------------------------------------------------------------';
-- PRINT @SQL
BEGIN TRY
DECLARE THE_DBS CURSOR STATIC LOCAL FORWARD_ONLY READ_ONLY
FOR
SELECT s.name
FROM sys.databases s
WHERE 1=1
AND s.state = 0
AND s.name NOT IN ('master', 'model', 'msdb', 'tempdb', 'distribution')
AND s.name NOT LIKE 'ReportServer%'
OPEN THE_DBS;
FETCH NEXT FROM THE_DBS INTO @name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @theSQL = 'EXEC ' + QUOTENAME(@name) +
'.sys.sp_executesql @SQL' + CHAR(10) +
',N''@spName varchar(100)'',' + CHAR(10) +
'''' + @spName + '''' +';' + CHAR(10)
-------------------------------------------
--do the insert here
-------------------------------------------
INSERT INTO #Radhe([DB],[THE_SCHEMA],[table_name],[TRIGGER_NAME],[trigger_definition] )
EXEC sys.sp_executesql @theSQL
, N'@SQL nvarchar(max)'
, @SQL
FETCH NEXT FROM THE_DBS INTO @name;
END
-------------------------------------------
BEGIN TRY
--clean it up
CLOSE THE_DBS;
DEALLOCATE THE_DBS;
END TRY
BEGIN CATCH
--do nothing
END CATCH
-------------------------------------------
END TRY
BEGIN CATCH
-------------------------------------------
BEGIN TRY
--clean it up
CLOSE THE_DBS;
DEALLOCATE THE_DBS;
END TRY
BEGIN CATCH
--do nothing
END CATCH
-------------------------------------------
DECLARE @ERRORMESSAGE NVARCHAR(512),
@ERRORSEVERITY INT,
@ERRORNUMBER INT,
@ERRORSTATE INT,
@ERRORPROCEDURE SYSNAME,
@ERRORLINE INT,
@XASTATE INT
SELECT
@ERRORMESSAGE = ERROR_MESSAGE(),
@ERRORSEVERITY = ERROR_SEVERITY(),
@ERRORNUMBER = ERROR_NUMBER(),
@ERRORSTATE = ERROR_STATE(),
@ERRORPROCEDURE = ERROR_PROCEDURE(),
@ERRORLINE = ERROR_LINE()
SET @ERRORMESSAGE =
(
SELECT CHAR(13) +
'Message:' + SPACE(1) + @ErrorMessage + SPACE(2) + CHAR(13) +
'Error:' + SPACE(1) + CONVERT(NVARCHAR(50),@ErrorNumber) + SPACE(1) + CHAR(13) +
'Severity:' + SPACE(1) + CONVERT(NVARCHAR(50),@ErrorSeverity) + SPACE(1) + CHAR(13) +
'State:' + SPACE(1) + CONVERT(NVARCHAR(50),@ErrorState) + SPACE(1) + CHAR(13) +
'Routine_Name:' + SPACE(1) + COALESCE(@ErrorProcedure,'') + SPACE(1) + CHAR(13) +
'Line:' + SPACE(1) + CONVERT(NVARCHAR(50),@ErrorLine) + SPACE(1) + CHAR(13) +
'Executed As:' + SPACE(1) + SYSTEM_USER + SPACE(1) + CHAR(13) +
'Database:' + SPACE(1) + DB_NAME() + SPACE(1) + CHAR(13) +
'OSTime:' + SPACE(1) + CONVERT(NVARCHAR(25),CURRENT_TIMESTAMP,121) + CHAR(13)
)
--We can also save the error details to a table for later reference here.
RAISERROR (@ERRORMESSAGE,16,1)
END CATCH
--------------------------------
-- by now the #Radhe table has been populated
--------------------------------
SELECT *
FROM #Radhe
WHERE trigger_definition LIKE @spName
マルチェロ、1つのスクリプトで目標を達成する必要がある場合は、データベースを反復処理し、各データベースのコンテキストでTSQLを実行してみてください。以下は、カーソルループ内の各データベースから/内のsp_executesqlを実行するsp_executesqlの例です。ここでは@Tsqlは静的であるため、カーソルループの外側で宣言されていることに注意してください。ただし、ループ内で動的に簡単に構築できます。このアプローチは簡単ではありません。少し複雑に思えるかもしれません。あなたを裁判官に任せます。
/*
Build the TSQL statement that you want to run on each database.
Here is an example that finds database users that are members of
specific fixed database roles and drops them from those roles.
Note the single quotes are quadrupled.
*/
DECLARE @Tsql NVARCHAR(MAX) = '
DECLARE @User SYSNAME, @Role SYSNAME
DECLARE curUsers CURSOR FAST_FORWARD READ_ONLY FOR
SELECT u.name UserName, r.name dbRole
FROM sys.database_principals u
JOIN sys.database_role_members rm
ON rm.member_principal_id = u.principal_id
JOIN sys.database_principals r
ON r.principal_id = rm.role_principal_id
WHERE r.name IN (''''db_accessadmin'''', ''''db_backupoperator'''', ''''db_securityadmin'''')
AND u.name NOT IN (''''dbo'''', ''''guest'''', ''''INFORMATION_SCHEMA'''', ''''public'''', ''''sys'''')
ORDER BY u.name, r.name
OPEN curUsers
FETCH NEXT FROM curUsers INTO @User, @Role
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_droprolemember @Role, @User
FETCH NEXT FROM curUsers INTO @User, @Role
END
CLOSE curUsers
DEALLOCATE curUsers
';
DECLARE @DB SYSNAME
DECLARE curDB CURSOR FOR
SELECT d.name
FROM master.sys.databases d
--Comment out/adjust this WHERE clause as needed.
WHERE d.name NOT IN ('master','tempdb')
OPEN curDB
FETCH NEXT FROM curDB INTO @DB, @DBOwner
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @DB
--Execute sp_executesql, which executes sp_executesql
--in the context of a specific database.
SET @Tsql = '[' + @DB + ']..sp_executesql N''' + @Tsql + ''''
EXEC sp_executesql @Tsql;
FETCH NEXT FROM curDB INTO @DB, @DBOwner
END
CLOSE curDB
DEALLOCATE curDB
GO
Red GateのSQL Search(無料のManagement Studioプラグイン)を確認することをお勧めします http://www.red-gate.com/products/sql-development/sql-search/
これにより、サーバー上の任意またはすべてのデータベースでストアドプロシージャコールを検索できます。必要に応じて、トリガー内のみを検索するように検索を制限できます。
Pinal Daveには、データベース間のオブジェクトの依存関係を特定する優れたスクリプトがあります。
SQL SERVER – sys.sql_expression_dependenciesを使用してSQL Serverで参照オブジェクトまたは参照オブジェクトを検索する
Sp_MSforeachdbストアドプロシージャの使用方法を確認してください。すべてのユーザーデータベースを簡単に繰り返し処理して、ニーズに対応します。