【问题标题】:Sql Server Temporal table historySql Server 时态表历史
【发布时间】:2021-01-07 11:50:09
【问题描述】:

有没有办法从表中识别历史记录中删除的行?

所以当我执行更新或删除时,它会将数据移动到历史记录中,我想知道历史记录中的哪些行被删除了

帮助

【问题讨论】:

    标签: sql sql-server tsql temporal-tables


    【解决方案1】:

    您可以使用output 子句。例如:

    declare @ids table (id int);
    
    delete from t
        output deleted.id into @ids
        where . . .;
    
    select *
    from @ids;
    

    【讨论】:

    • 我想在临时表中执行此操作,而不仅仅是在删除时/删除之后。
    【解决方案2】:

    使用基于PK的时间表和历史表之间的半反连接。

    【讨论】:

    • 如果该行已被删除,这将如何告诉我?
    • 只有被删除的行才会出现在查询结果数据集中。如果您想了解更多详细信息,请将您的表的 DDL 与时间设计一起发布,我会给您查询...
    【解决方案3】:

    举个例子……

    CREATE SCHEMA _CHRONO;
    GO
    
    CREATE TABLE dbo.TEMPO
    (
    ID          INT IDENTITY PRIMARY KEY,
    SOME_DATA   VARCHAR(32),
    _DH_DEB     DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    _DH_FIN     DATETIME2 GENERATED ALWAYS AS ROW END   HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (_DH_DEB, _DH_FIN)
    )
    WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = _CHRONO.TEMPO));
    GO
    
    INSERT INTO dbo.TEMPO VALUES ('a data'), ('another data')
    GO
    
    DELETE FROM dbo.TEMPO WHERE SOME_DATA LIKE '%other%'
    GO
    

    现在查询检索已删除的行:

    SELECT CT.*
    FROM   _CHRONO.TEMPO AS CT
           LEFT OUTER JOIN dbo.TEMPO AS T
              ON CT.ID = T.ID
    

    检索最后一个版本的已删除行需要添加一些额外的 SQL 条件

    【讨论】:

    • What is I do an update (UPDATR dbo.TEMPO SET SOME_DATA= 'another kind of data' WHERE SOME_DATA='another data'),这也会在_CHRONO.TEMPO中创建一行
    • 我希望 SQL Server 有一些东西(比如 ROW_NUMBER() )来识别使数据移动到历史记录的操作
    • 本质上,RDBMS 将只有您设计的内容。这是 RDBMS 的创建者 F. E. Codd 的一般一致性规则。尽管如此,某些 RDBMS 确实有隐藏的列,这是一团糟(以 Oracle 和 PostGreSQL 为例)...
    【解决方案4】:

    如果您想知道历史记录中删除了哪些行,只需创建一个审计表并在真实表中设置触发器即可。

    例如,您有一个名为“PeopleTbl”的表。

    1- 您将创建一个审计表来存储“PeopleTbl”的历史记录。让我们创建一个名为“PeopleAuditTbl”的表。

    “PeopleAuditTbl”的结构。应该包含您希望跟踪的所有列以及一个时间字段和一个 TypeField(删除、插入或更新)。

    2- 现在在您的“PeopleTbl”中。您将创建一个存储更新或删除的触发器(如果需要,您还可以存储插入的记录。

    删除的触发器应该是这样的。

    ALTER TRIGGER T_PeopleTbl
        ON PeopleTbl
        AFTER DELETE
    AS
    INSERT INTO PeopleAuditTbl(
            //Fields you want to store
            Date,
            TypeField
        )
        SELECT
            //Fields you want to store
            GETDate(),
            'DELETE'
        FROM DELETED
    
    

    【讨论】:

      【解决方案5】:

      如果您希望使用 Temporal History 表来识别已从 Main 表中删除的记录,以下示例演示了如何实现这一点:

      -- Create a Temporal Table for demonstration purposes
      CREATE TABLE dbo.Invoice
      (
        InvoiceId int identity(1,1) PRIMARY KEY CLUSTERED
        , InvoiceDate date NOT NULL
        -- Other fields...
        , SysStartTime datetime2 GENERATED ALWAYS AS ROW START
        , SysEndTime datetime2 GENERATED ALWAYS AS ROW END
        , PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
       )
      WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.InvoiceHistory));
      go
      
      -- Create some dummy data
      insert into Invoice(InvoiceDate) values ('2020-01-01'),('2020-02-01')
      go
      WAITFOR DELAY '00:00:03'
      go
      delete from Invoice where InvoiceId=1
      go
      
      -- Get Current Records
      select * from Invoice
      
      -- Get Deleted Records
      ;with cte as
      (
          select InvoiceId, MAX(SysEndTime) [SysEndTime]
          from Invoice FOR SYSTEM_TIME ALL
          group by InvoiceId
          having MAX(SysEndTime) < '9999-12-31'
      )
      select i.*
      from Invoice FOR SYSTEM_TIME ALL i
      inner join cte c on (i.InvoiceId=c.InvoiceId and i.SysEndTime=c.SysEndTime)
      

      基本上,我们正在查看 latest 版本为 no 的任何记录的主表和历史表(select * from Invoice FOR SYSTEM_TIME ALL)的联合更长时间有效 (MAX(SysEndTime) )

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-05
        相关资源
        最近更新 更多