Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何监视SQL Server中的表结构更改?_Sql Server - Fatal编程技术网

Sql server 如何监视SQL Server中的表结构更改?

Sql server 如何监视SQL Server中的表结构更改?,sql-server,Sql Server,我想监视SQL Server中某个表结构的更改 例如,假设我有下表 现存的 改变 是否可以知道是否使用SQL查询将新列添加到此表中?我想找到新增加的专栏的具体内容 我试过这个;但它没有给我新添加的列名 SELECT OBJECT_NAME(sc.[object_id]) as [table] ,sc.[name] as [column] ,so.modify_date ,so.create_date FROM [sys].[columns] sc JOIN

我想监视SQL Server中某个表结构的更改

例如,假设我有下表

现存的

改变

是否可以知道是否使用SQL查询将新列添加到此表中?我想找到新增加的专栏的具体内容

我试过这个;但它没有给我新添加的列名

SELECT
    OBJECT_NAME(sc.[object_id]) as [table]
    ,sc.[name] as [column]
    ,so.modify_date
    ,so.create_date
  FROM [sys].[columns] sc
  JOIN [sys].[objects] so
  ON sc.[object_id] = so.[object_id]
  ORDER BY so.modify_date DESC

有什么想法吗?

您可以在数据库上使用ddl触发器

create table dbo.logtablechanges
(
    tableobject_id int,
    tablename sysname,
    columnname sysname,--log a single column alteration
    theaction varchar(50),
    actionbylogin sysname constraint df_logtablechanges_actionbylogin default(original_login()),
    thestatement nvarchar(max),
    thedate datetime constraint df_logtablechanges_thedate default(getdate())
);
go

create table dbo.guineapigtbl(id int identity);
insert into dbo.guineapigtbl default values;
select * from guineapigtbl;
go

create trigger trig_db_alter_table on database
for ALTER_TABLE 
as
begin

    declare @d xml = EVENTDATA();

    declare @tblschemaname sysname, 
            @tblname sysname, 
            @action varchar(20),
            @colname sysname,
            @sqlcommand nvarchar(max);

    --for multiple columns      
    select 
        @tblschemaname = @d.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname'),
        @tblname = @d.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
        @action = @d.value('local-name((/EVENT_INSTANCE/AlterTableActionList/*)[1])', 'varchar(20)'),
        --change this for multiple columns (depends on the logging)
        @colname = @d.value('(/EVENT_INSTANCE/AlterTableActionList/*[1]/Columns/Name)[1]', 'sysname'),
        @sqlcommand = @d.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(max)');


    if object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)) = object_id('dbo.guineapigtbl')
      and @colname is not null
    begin
        insert into dbo.logtablechanges
        (
            tableobject_id, 
            tablename, columnname,  theaction, thestatement
        )
        values
        (
            object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)),
            @tblname, @colname, @action, @sqlcommand
        )

    end

end
go


--testing
alter table dbo.guineapigtbl add col1 int;
alter table dbo.guineapigtbl add col2 varchar(10);
alter table dbo.guineapigtbl alter column col1 bigint;
alter table dbo.guineapigtbl drop column col1;

--multiple
alter table dbo.guineapigtbl add col3 int, col4 int;

--check log
select *
from logtablechanges

--cleanup
/*
drop table dbo.logtablechanges
drop table dbo.guineapigtbl
drop trigger trig_db_alter_table on database

go
*/

非常感谢您的代码! 我编辑了将监视数据库的所有表的触发器,而不仅仅是位于=object_id'dbo.guineapigtbl'的特定表

ALTER trigger trig_db_alter_table on database
for ALTER_TABLE 
as
begin

    declare @d xml = EVENTDATA();

    declare @tblschemaname sysname, 
            @tblname sysname, 
            @action varchar(20),
            @colname sysname,
            @sqlcommand nvarchar(max),
            
            @WHILE_Count int,
            @WHILE_Count_Max int;

    --for multiple columns      
    select 
        @tblschemaname = @d.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname'),
        @tblname = @d.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
        @action = @d.value('local-name((/EVENT_INSTANCE/AlterTableActionList/*)[1])', 'varchar(20)'),
        --change this for multiple columns (depends on the logging)
        @colname = @d.value('(/EVENT_INSTANCE/AlterTableActionList/*[1]/Columns/Name)[1]', 'sysname'),
        @sqlcommand = @d.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(max)');

    CREATE TABLE #TMP_list_of_tables_in_DB
        (ID INT IDENTITY(1,1)
        ,object_id_table int
        )

    INSERT INTO #TMP_list_of_tables_in_DB
        (object_id_table)
    SELECT 
        (object_id)
    FROM [DBNAME].sys.objects
        WHERE TYPE IN('P','T','FN','u')
        AND TYPE_DESC = 'USER_TABLE'

    SET @WHILE_Count = 1
    SET @WHILE_Count_Max = (SELECT MAX(ID) FROM #TMP_list_of_tables_in_DB)

    WHILE @WHILE_Count <= @WHILE_Count_Max

    BEGIN

    if object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)) = (SELECT object_id_table FROM #TMP_list_of_tables_in_DB WHERE ID = @WHILE_Count)
      and @colname is not null
    begin
        insert into dbo.logtablechanges
        (
            tableobject_id, 
            tablename, columnname,  theaction, thestatement
        )
        values
        (
            object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)),
            @tblname, @colname, @action, @sqlcommand
        )

    end

    SET @WHILE_Count = @WHILE_Count + 1

    END

    DROP TABLE #TMP_list_of_tables_in_DB

end

这可能会有所帮助:任何数量的代码都无法弥补未管理的开发过程。它也不会补偿在没有与团队其他成员沟通或协商的情况下进行模式更改的开发人员。您的模式应该是源代码控制的-就像您的应用程序代码一样。
create table dbo.logtablechanges
(
    tableobject_id int,
    tablename sysname,
    columnname sysname,--log a single column alteration
    theaction varchar(50),
    actionbylogin sysname constraint df_logtablechanges_actionbylogin default(original_login()),
    thestatement nvarchar(max),
    thedate datetime constraint df_logtablechanges_thedate default(getdate())
);
go

create table dbo.guineapigtbl(id int identity);
insert into dbo.guineapigtbl default values;
select * from guineapigtbl;
go

create trigger trig_db_alter_table on database
for ALTER_TABLE 
as
begin

    declare @d xml = EVENTDATA();

    declare @tblschemaname sysname, 
            @tblname sysname, 
            @action varchar(20),
            @colname sysname,
            @sqlcommand nvarchar(max);

    --for multiple columns      
    select 
        @tblschemaname = @d.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname'),
        @tblname = @d.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
        @action = @d.value('local-name((/EVENT_INSTANCE/AlterTableActionList/*)[1])', 'varchar(20)'),
        --change this for multiple columns (depends on the logging)
        @colname = @d.value('(/EVENT_INSTANCE/AlterTableActionList/*[1]/Columns/Name)[1]', 'sysname'),
        @sqlcommand = @d.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(max)');


    if object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)) = object_id('dbo.guineapigtbl')
      and @colname is not null
    begin
        insert into dbo.logtablechanges
        (
            tableobject_id, 
            tablename, columnname,  theaction, thestatement
        )
        values
        (
            object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)),
            @tblname, @colname, @action, @sqlcommand
        )

    end

end
go


--testing
alter table dbo.guineapigtbl add col1 int;
alter table dbo.guineapigtbl add col2 varchar(10);
alter table dbo.guineapigtbl alter column col1 bigint;
alter table dbo.guineapigtbl drop column col1;

--multiple
alter table dbo.guineapigtbl add col3 int, col4 int;

--check log
select *
from logtablechanges

--cleanup
/*
drop table dbo.logtablechanges
drop table dbo.guineapigtbl
drop trigger trig_db_alter_table on database

go
*/
ALTER trigger trig_db_alter_table on database
for ALTER_TABLE 
as
begin

    declare @d xml = EVENTDATA();

    declare @tblschemaname sysname, 
            @tblname sysname, 
            @action varchar(20),
            @colname sysname,
            @sqlcommand nvarchar(max),
            
            @WHILE_Count int,
            @WHILE_Count_Max int;

    --for multiple columns      
    select 
        @tblschemaname = @d.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname'),
        @tblname = @d.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
        @action = @d.value('local-name((/EVENT_INSTANCE/AlterTableActionList/*)[1])', 'varchar(20)'),
        --change this for multiple columns (depends on the logging)
        @colname = @d.value('(/EVENT_INSTANCE/AlterTableActionList/*[1]/Columns/Name)[1]', 'sysname'),
        @sqlcommand = @d.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(max)');

    CREATE TABLE #TMP_list_of_tables_in_DB
        (ID INT IDENTITY(1,1)
        ,object_id_table int
        )

    INSERT INTO #TMP_list_of_tables_in_DB
        (object_id_table)
    SELECT 
        (object_id)
    FROM [DBNAME].sys.objects
        WHERE TYPE IN('P','T','FN','u')
        AND TYPE_DESC = 'USER_TABLE'

    SET @WHILE_Count = 1
    SET @WHILE_Count_Max = (SELECT MAX(ID) FROM #TMP_list_of_tables_in_DB)

    WHILE @WHILE_Count <= @WHILE_Count_Max

    BEGIN

    if object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)) = (SELECT object_id_table FROM #TMP_list_of_tables_in_DB WHERE ID = @WHILE_Count)
      and @colname is not null
    begin
        insert into dbo.logtablechanges
        (
            tableobject_id, 
            tablename, columnname,  theaction, thestatement
        )
        values
        (
            object_id(quotename(@tblschemaname) + '.' + quotename(@tblname)),
            @tblname, @colname, @action, @sqlcommand
        )

    end

    SET @WHILE_Count = @WHILE_Count + 1

    END

    DROP TABLE #TMP_list_of_tables_in_DB

end