【问题标题】:Find the date/time a table's column was created查找创建表列的日期/时间
【发布时间】:2009-09-15 06:39:33
【问题描述】:

如何在 SQL Server 中查询 SQL Server 2005 表列的创建日期?

我尝试使用sp_columns [tablename] 获取该信息,但创建日期未包含在此存储过程中。

如何做到这一点?

【问题讨论】:

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

有一个名为 sys.Columns 的系统表,您可以从中获取列信息。 如果您想查看特定表的列,可以执行以下操作:

SELECT col.* from sys.objects obj 
inner join sys.columns col 
on obj.object_Id=col.object_Id 
and obj.Name=@tableName

或者你可以像这样获取表格信息:

SELECT * FROM sys.objects WHERE Name=@tableName

但我找不到任何有关列创建日期的信息。

更新: This 可能会有所帮助。

【讨论】:

  • 为什么不使用“sys.tables”作为表信息?为什么总是去 sys.objects ???
  • 我不知道!我猜这是一个旧习惯:)
  • +1 - 列创建日期似乎不可用并且提供的链接
  • @marc_s 问题是创建特定列的时间,而不是创建表的时间。
  • @marc_s 哦,是的,所以您的意思是使用 sys.tables,而答案中的查询使用 sys.objects。现在更有意义了。
【解决方案2】:

SQL Server 不会跟踪对表的特定更改。如果您想要或需要这种级别的详细信息,您需要创建一个 DDL 触发器(在 SQL Server 2005 中引入),该触发器可以捕获某些特定事件甚至事件类别,并将这些更改记录到您创建的历史表中。

DDL 触发器是“后”触发器;没有“代替”选项。但是,如果您想禁止某项操作,只需发出 ROLLBACK 即可取消所发生的事情。

DDL Triggers 的 MSDN 页面有很多关于如何捕获特定事件(即ALTER TABLE)和使用返回 XML 的 EVENTDATA 函数来获取触发事件的详细信息的信息触发器,包括已执行的确切 SQL 查询。事实上,Use the EVENTDATA Function 的 MSDN 页面甚至有创建 DDL 触发器以捕获 ALTER TABLE 语句的简单示例(在“ ALTER TABLE 和 ALTER DATABASE 事件”部分)并创建 DDL 触发器以将事件捕获到日志表(在“示例”部分中)。由于所有 ALTER TABLE 命令都会触发此触发器,因此您需要解析出哪些是特定于您要查找的内容。而且,也许现在您知道这是一个选项,需要捕获的不仅仅是添加列(即删除列、更改数据类型和/或 NULLability 等)。

需要注意的是,您可以为ALTER_TABLE等数据库范围的事件创建一个DLL触发器ON ALL SERVER

如果您想查看任何事件或事件类的 XML 结构,请转到:

http://schemas.microsoft.com/sqlserver/2006/11/eventdata/

并单击“当前版本:”链接。如果您想查看特定事件或事件类,只需在触发器的“FOR”子句(包括下划线)中使用的事件名称上进行搜索(通常是浏览器中的 Control-F)。以下是ALTER_TABLE 事件的架构:

<xs:complexType name="EVENT_INSTANCE_ALTER_TABLE">
<xs:sequence>
<!--  Basic Envelope  -->
<xs:element name="EventType" type="SSWNAMEType"/>
<xs:element name="PostTime" type="xs:string"/>
<xs:element name="SPID" type="xs:int"/>
<!--  Server Scoped DDL  -->
<xs:element name="ServerName" type="PathType"/>
<xs:element name="LoginName" type="SSWNAMEType"/>
<!--  DB Scoped DDL  -->
<xs:element name="UserName" type="SSWNAMEType"/>
<!--  Main Body  -->
<xs:element name="DatabaseName" type="SSWNAMEType"/>
<xs:element name="SchemaName" type="SSWNAMEType"/>
<xs:element name="ObjectName" type="SSWNAMEType"/>
<xs:element name="ObjectType" type="SSWNAMEType"/>
<xs:element name="Parameters" type="EventTag_Parameters" minOccurs="0"/>
<xs:element name="AlterTableActionList" type="AlterTableActionListType" minOccurs="0"/>
<xs:element name="TSQLCommand" type="EventTag_TSQLCommand"/>
</xs:sequence>
</xs:complexType>

这是一个非常简单的测试,看看它是如何工作的以及生成的 EventData XML 的样子:

IF (EXISTS(
   SELECT *
   FROM   sys.server_triggers sst
   WHERE  sst.name = N'CaptureAlterTable'
   ))
BEGIN
  DROP TRIGGER CaptureAlterTable ON ALL SERVER;
END;
GO

CREATE TRIGGER CaptureAlterTable
ON ALL SERVER -- capture events for all databases
FOR ALTER_TABLE -- only capture ALTER TABLE events
AS
  PRINT CONVERT(NVARCHAR(MAX), EVENTDATA()); -- Display in "Messages" tab in SSMS
GO

首先我们在 tempdb 中创建一个简单的真实表(临时表不会捕获这些事件):

USE [tempdb];
CREATE TABLE dbo.MyAlterTest (Col2 INT NULL);

接下来我们添加一列。我们从不同的数据库执行此操作,以确保 XML 捕获对象存在的数据库而不是当前数据库。请注意单词 alTeR Table tempDB.dbo.MyALTERTest ... DATEcreated 的大小写,以便与 XML 中的内容进行比较。

USE [master];
alTeR Table tempDB.dbo.MyALTERTest ADD DATEcreated DATETIME NOT NULL;

您应该在“消息”选项卡(我添加的 cmets)中看到以下内容:

<EVENT_INSTANCE>
  <EventType>ALTER_TABLE</EventType>
  <PostTime>2014-12-15T10:53:04.523</PostTime>
  <SPID>55</SPID>
  <ServerName>_{server_name}_</ServerName>
  <LoginName>_{login_name}_</LoginName>
  <UserName>dbo</UserName>
  <DatabaseName>tempdb</DatabaseName> <!-- casing is based on database definition -->
  <SchemaName>dbo</SchemaName>
  <ObjectName>MyAlterTest</ObjectName> <!-- casing is based on object definition -->
  <ObjectType>TABLE</ObjectType>
  <AlterTableActionList>
    <Create>
      <Columns>
        <Name>DATEcreated</Name> <!-- casing is taken from executed query -->
      </Columns>
    </Create>
  </AlterTableActionList>
  <TSQLCommand>
    <SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/>
    <CommandText>alTeR Table tempDB.dbo.MyALTERTest ADD DATEcreated DATETIME NOT NULL;&#x0D;
</CommandText>
  </TSQLCommand>
</EVENT_INSTANCE>

如果捕获每列的详细信息(即 NULL / NOT NULL、数据类型等)而不仅仅是名称,那就太好了,但如果需要,可以从 CommandText 元素中解析出这些细节。

【讨论】:

    【解决方案3】:

    我认为没有办法获得各个列本身的修改或创建日期。 thisthis 答案中给出的查询返回与包含列而不是列的表相关的日期。因为 sys.columns 表对于表中的所有列都具有相同的 id。您可以通过运行此查询来验证这一点

    select col.object_id, col.name, col.column_id
    from sys.columns col
    where col.object_id = 
    (select o.object_id from sys.objects o where o.Name = @tableName)
    

    【讨论】:

    • or: where col.object_id = OBJECT_ID('table_name') - 对我来说似乎更容易
    【解决方案4】:

    聚会迟到了,但找到了对我有帮助的东西。如果您可以说该列是对表格的最后一次更改,那么sys.tables(modify_date) 是可行的。

    【讨论】:

      【解决方案5】:
      SELECT so.name,so.modify_date
      FROM sys.objects as so
          INNER JOIN INFORMATION_SCHEMA.TABLES as ist
      ON ist.TABLE_NAME=so.name where ist.TABLE_TYPE='BASE TABLE' AND
       TABLE_CATALOG='dbName' order by so.modify_date desc;
      

      【讨论】:

        【解决方案6】:

        我认为这些信息不可用,除非您有可以浏览事务日志的工具,例如日志资源管理器。这不是 tsql 的事情。

        【讨论】:

          【解决方案7】:

          我遇到了一个问题,我必须将表复制到另一台服务器,我想做这个确切的事情,但是 sys 表中没有任何内容可以显示添加或更改列的时间。因为我知道我当前的表有正确的列,所以我在 do 循环中执行了以下操作:

          declare @CurrentTableCount int = 0,
                  @SchemaCheckTableCount = 0
          
            select top 1 * into TableNameSchemaCheck from OpenQuery
           (Database, 'select * from TableName where 1 = 2')
          
           select @CurrentTableCount = (select count(1) from sys.syscolumns c
                                          inner join sys.sysobjects o on c.id = o.id
                                            where o.xtype = 'U'
                                              and o.name = 'TableName')
          
           select @SchemaCheckTableCount = (select count(1) from sys.syscolumns c
                                             inner join sys.sysobjects o on c.id = o.id
                                             where o.xtype = 'U'
                                               and o.name = 'TableNameSchemaCheck')
          
              if @CurrentTableCount <> @SchemaCheckTableCount
               begin
          
                insert into SchemaCheckLog
                 values ('CompanyContext', getdate(), 'Schema for TableName table has changed.', 0)
          
                 end
          
               drop table TableNameSchemaCheck
          
           end
          

          我构建了一个程序,通过电子邮件向我发送该表中的结果,然后我知道源表的架构已更改,我需要在目标中更改它。

          然后您可以对此进行扩展并找到不同的列名,但我的用例不需要。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-16
            • 1970-01-01
            • 2021-01-07
            • 2015-08-19
            • 1970-01-01
            相关资源
            最近更新 更多