web-dev-qa-db-ja.com

特定のストアドプロシージャを呼び出すすべてのトリガーを特定するにはどうすればよいですか?

一部の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
2

マルチェロ、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
1
Dave Mason

Red GateのSQL Search(無料のManagement Studioプラグイン)を確認することをお勧めします http://www.red-gate.com/products/sql-development/sql-search/

これにより、サーバー上の任意またはすべてのデータベースでストアドプロシージャコールを検索できます。必要に応じて、トリガー内のみを検索するように検索を制限できます。

1
Eric Cobb

Pinal Daveには、データベース間のオブジェクトの依存関係を特定する優れたスクリプトがあります。

SQL SERVER – sys.sql_expression_dependenciesを使用してSQL Serverで参照オブジェクトまたは参照オブジェクトを検索する

0
MattyZDBA

Sp_MSforeachdbストアドプロシージャの使用方法を確認してください。すべてのユーザーデータベースを簡単に繰り返し処理して、ニーズに対応します。

0
SQLRockstar