代码之家  ›  专栏  ›  技术社区  ›  BuddyJoe

Microsoft SQL Server-谁创建了存储过程?

  •  8
  • BuddyJoe  · 技术社区  · 16 年前

    有没有一种好的方法可以告诉谁在SQL Server 2005中创建了存储过程(这在2008年也有效)?在SQL Management Studio中,我可以在进程上用鼠标右键/属性来获取创建日期/时间,但我如何发现创建者?

    5 回复  |  直到 15 年前
        1
  •  6
  •   Sam    16 年前

    现在对你来说可能太晚了,但是你可以跟踪DDL活动。

    我们的管理数据库中有一个表,可以将所有活动放入其中。它使用一个DDL触发器,2005年才出现。这些脚本在管理数据库中创建一个表(对于我来说是SQL数据库),在模型数据库上创建一个触发器,在现有数据库上创建触发器。我还在末尾创建了一个sp msforeachdb语句来禁用所有语句。

    一个警告 -您的数据库需要处于90的兼容模式(在每个数据库的选项中),否则您可能会开始出错。作为语句一部分的execute中的帐户还需要访问权才能插入到管理表中。

    USE [SQL_DBA]
    GO
    /****** Object:  Table [dbo].[DDL_Login_Log]    Script Date: 03/03/2009 17:28:10 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[DDL_Login_Log](
        [DDL_Id] [int] IDENTITY(1,1) NOT NULL,
        [PostTime] [datetime] NOT NULL,
        [DB_User] [nvarchar](100) NULL,
        [DBName] [nvarchar](100) NULL,
        [Event] [nvarchar](100) NULL,
        [TSQL] [nvarchar](2000) NULL,
        [Object] [nvarchar](1000) NULL,
     CONSTRAINT [PK_DDL_Login_Log] PRIMARY KEY CLUSTERED 
    (
        [DDL_Id] ASC,
        [PostTime] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    --------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    --This creates the trigger on the model database so all new DBs get it
    USE [model]
    GO
    /****** Object:  DdlTrigger [ddl_DB_User]    Script Date: 03/03/2009 17:26:13 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TRIGGER [ddl_DB_User] 
    ON DATABASE
    FOR DDL_DATABASE_SECURITY_EVENTS
    AS 
    
    DECLARE @data XML
    declare @user nvarchar(100)
    
    SET @data = EVENTDATA()
    select @user = convert(nvarchar(100), SYSTEM_USER)
    
    execute as login='domain\sqlagent'
    INSERT sql_dba.dbo.DDL_Login_Log 
       (PostTime, DB_User, DBName, Event, TSQL,Object) 
       VALUES 
       (@data.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'), 
       @user,
        db_name(),
        @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'), 
       @data.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'),
        @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(1000)')
    )
    
    GO
    SET ANSI_NULLS OFF
    GO
    SET QUOTED_IDENTIFIER OFF
    GO
    
    
    --------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    --CREATE TRIGGER IN ALL NON SYSTEM DATABASES
    
    DECLARE @dataname varchar(255),
    @dataname_header varchar(255),
    @command VARCHAR(MAX),
    @usecommand VARCHAR(100)
    SET @command = '';
    DECLARE datanames_cursor CURSOR FOR SELECT name FROM sys.databases 
    WHERE name not in ('master', 'pubs', 'tempdb', 'model','msdb')
    OPEN datanames_cursor
    FETCH NEXT FROM datanames_cursor INTO @dataname
    WHILE (@@fetch_status = 0)
    BEGIN
    
    PRINT '----------BEGIN---------'
    
    PRINT 'DATANAME variable: ' + @dataname;
    
    EXEC ('USE ' + @dataname);
    
    PRINT 'CURRENT db: ' + db_name();
    
    SELECT @command = 'CREATE TRIGGER DBA_Audit ON DATABASE
    FOR DDL_DATABASE_LEVEL_EVENTS
    AS
    DECLARE @data XML
    DECLARE @cmd NVARCHAR(1000)
    DECLARE @posttime NVARCHAR(24)
    DECLARE @spid NVARCHAR(6)
    DECLARE @loginname NVARCHAR(100)
    DECLARE @hostname NVARCHAR(100)
    SET @data = EVENTDATA()
    SET @cmd = @data.value(''(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]'', ''NVARCHAR(1000)'')
    SET @cmd = LTRIM(RTRIM(REPLACE(@cmd,'''','''')))
    SET @posttime = @data.value(''(/EVENT_INSTANCE/PostTime)[1]'', ''DATETIME'')
    SET @spid = @data.value(''(/EVENT_INSTANCE/SPID)[1]'', ''nvarchar(6)'')
    SET @loginname = @data.value(''(/EVENT_INSTANCE/LoginName)[1]'',
        ''NVARCHAR(100)'')
    SET @hostname = HOST_NAME()
    INSERT INTO [DBA_AUDIT].dbo.AuditLog(Command, PostTime,HostName,LoginName)
     VALUES(@cmd, @posttime, @hostname, @loginname);'
    
     EXEC (@command);
     FETCH NEXT FROM datanames_cursor INTO @dataname;
    PRINT '----------END---------'
    END
    CLOSE datanames_cursor
    DEALLOCATE datanames_cursor
    
    --------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    
    ----Disable all triggers when things go haywire
    sp_msforeachdb @command1='use [?]; IF  EXISTS (SELECT * FROM sys.triggers WHERE name = N''ddl_DB_User'' AND parent_class=0)disable TRIGGER [ddl_DB_User] ON DATABASE'
    
        2
  •  3
  •   Rory    16 年前

    我认为这在SQL 2005中不可用。当然,它在SQL Management Studio的属性中不可用,在sys.objects表或我能看到的任何其他表中都不可用。

        3
  •  3
  •   Mitch Wheat    16 年前

    如果不是很久以前创建的,请尝试以下操作:

    DECLARE @path varchar(256)
    
    SELECT @path = path
    FROM sys.traces
    where id = 1
    
    SELECT *
    FROM fn_trace_gettable(@path, 1)
    

    它选择当前(开箱即用)默认跟踪。如果它是最近创建的(并且服务器最近没有重新启动),那么存储过程对象名和创建它的登录名将在跟踪数据中。

        4
  •  2
  •   mrdenny    16 年前

    与Sam的想法相同,您可以使用DDL触发器捕获所需信息,然后将该数据发送到SQL Service Broker队列,该队列可以将其转发到管理数据库(如果需要,该数据库可能位于另一台服务器上),该数据库将保存所有DDL更改。

    这将删除权限问题,因为DDL触发器将数据加载到本地数据库的ServiceBroker队列中,而SQL将处理将消息移动到其他数据库的操作。

    这个方法会有更多的设置,但是一旦设置,不管是谁更改了对象,它都会工作。

        5
  •  0
  •   Attila Csipak    15 年前

    如何从邮件中获取这段信息(尤其是几年后)是不可能的。

    但是,可以使用SQL Server事件探查器跟踪DDL操作。在事件选择中,检查以下事件:

    对象/对象:已更改

    对象/对象:已创建

    对象/对象:已删除

    还有许多自定义选项:您可以将输出保存到文件或表中,并根据任何列等进一步筛选输出。