如何根据另一个SQL Server表的单个列中的更改添加行和时间戳一个SQL Server表

问题描述 投票:0回答:2

[更新:2009年2月20日]我找到了解决这个问题的一个非常简单的解决方案。

CREATE TRIGGER TriggerClaims_History on Claims
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON
    INSERT INTO Claims_History
    SELECT name, status, claim_date
    FROM Claims
    EXCEPT SELECT name, status, claim_date FROM Claims_History
END
GO

我正在为我正在处理的项目站起来一个SQL Server数据库。重要信息:我有3个表 - 注册,取消和索赔。服务器上有文件每天填充这些表。这些文件不是增量(即每天放在服务器上的每个新文件都包含来自所有以前文件的数据),因此,我可以简单地删除所有表,创建表,然后每天从文件中填充表。我的问题是关于我的索赔表 - 因为每晚会丢弃和创建表格,我需要一种方法来跟踪所有不同的状态变化。

我正在努力找出解决这个问题的最佳方法。

我正在考虑创建一个每晚都不会删除的claim_history表。基本上我希望每次将初始新记录添加到声明表时填充claim_history表。然后我想扫描声明表并在claim_history表中添加一行,当且仅当状态列中有更改时(即claims.status!= claims_history.status)。

第1天:

select * from claims          

id | name     | status
 1 | jane doe | received

select * from claims_history  

id | name     | status   | timestamp
 1 | jane doe | received | datetime

第2天:

select * from claims          

id | name     | status
 1 | jane doe | processed

select * from claims_history  

id | name     | status    | timestamp
 1 | jane doe | received  | datetime
 1 | jane doe | processed | datetime

是否有可以执行此操作的SQL脚本?我还想在每次添加新行时(状态更改)自动在claim_history表中填充时间戳字段。我知道我可以写一个python脚本来处理这样的事情,但是如果可能的话我想把它保存在SQL中。谢谢。

sql sql-server tsql
2个回答
0
投票

根据你的问题,你需要在更新列claim.status之后创建一个触发器,这很简单,使用此链接来了解并查看如何进行简单的触发点击此处create asimple sql server trigger

然后好像在查询中操作dateTime有很多问题,建议你使用UNIX时间而不是使用datetime你可以使用Long或bigInt UNix时间存储日期作为数字来知道当前时间简单使用查询SELECT UNIX_TIMESTAMP ()


0
投票

一种非常常见的方法是使用临时表和生产(或最终)表。所有ETL都将截断并加载登台表(volatile),然后执行存储过程,该过程仅将新记录添加到最终表中。这要求您以这种方式处理的所有数据都具有某种形式的密钥,可以明确地标识一行。

如果您的文件突然改变格式或格式错误会怎样?您将删除表,并且在修复ETL之前无法将其加载。这种方法可以避免这种情况,因为加载登台表时进程会失败,并且不会影响最终表。您还可以出于历史原因保留已删除的记录,而不是删除它们。

我更喜欢将登台表分成适当的架构,例如:

CREATE SCHEMA Staging
GO

CREATE TABLE Staging.Claims (
    ID INT,
    Name VARCHAR(100),
    Status VARCHAR(100))

现在,您将从文件中加载到这些临时表中的所有负载,首先截断它们:

TRUNCATE TABLE Staging.Claims

BULK INSERT Staging.Claims
FROM '\\SomeFile.csv'
WITH
    --...

加载此表后,您将执行一个特定的SP,它会在暂存内容和最终表之间添加增量。您可以在此处添加所需的逻辑,例如仅插入新记录,或插入已在另一个表上更新的现有值。例如:

CREATE TABLE dbo.Claims (
    ClaimAutoID INT IDENTITY PRIMARY KEY,
    ClaimID INT,
    Name VARCHAR(100),
    Status VARCHAR(100),
    WasDeleted BIT DEFAULT 0,
    ModifiedDate DATETIME,
    CreatedDate DATETIME DEFAULT GETDATE())
GO

CREATE PROCEDURE Staging.UpdateClaims
AS
BEGIN

    BEGIN TRY

        BEGIN TRANSACTION

            -- Update changed values
            UPDATE C SET
                Name = S.Name,
                Status = S.Status,
                ModifiedDate = GETDATE()
            FROM
                Staging.Claims AS S
                INNER JOIN dbo.Claims AS C ON S.ID = C.ClaimID -- This has to be by the key columns
            WHERE
                ISNULL(C.Name, '') <> ISNULL(S.Name, '') AND
                ISNULL(C.Status, '') <> ISNULL(S.Status, '')

            -- Insert new records
            INSERT INTO dbo.Claims (
                ClaimID,
                Name,
                Status)
            SELECT
                ClaimID = S.ID,
                Name = S.Name,
                Status = S.Status
            FROM
                Staging.Claims AS S
            WHERE
                NOT EXISTS (SELECT 'not yet loaded' FROM dbo.Claims AS C WHERE S.ID = C.ClaimID) -- This has to be by the key columns

            -- Mark deleted records as deleted
            UPDATE C SET
                WasDeleted = 1,
                ModifiedDate = GETDATE()
            FROM
                dbo.Claims AS C
            WHERE
                NOT EXISTS (SELECT 'not anymore on files' FROM Staging.Claims AS S WHERE S.ClaimID = C.ClaimID) -- This has to be by the key columns


        COMMIT

    END TRY

    BEGIN CATCH

        DECLARE @v_ErrorMessage VARCHAR(MAX) = ERROR_MESSAGE()

        IF @@TRANCOUNT > 0
            ROLLBACK

        RAISERROR (@v_ErrorMessage, 16, 1)

    END CATCH

END

这样你总是使用dbo.Claims并且记录永远不会丢失(只是更新或插入)。


如果您需要检查特定声明的最后状态,可以创建一个视图:

CREATE VIEW dbo.vClaimLastStatus 
AS
WITH ClaimsOrdered AS
(
    SELECT
        C.ClaimAutoID,
        C.ClaimID,
        C.Name,
        C.Status,
        C.ModifiedDate,
        C.CreatedDate,
        DateRanking = ROW_NUMBER() OVER (PARTITION BY C.ClaimID ORDER BY C.CreatedDate DESC)
    FROM
        dbo.Claims AS C
)
SELECT
    C.ClaimAutoID,
    C.ClaimID,
    C.Name,
    C.Status,
    C.ModifiedDate,
    C.CreatedDate,
FROM
    ClaimsOrdered AS C
WHERE
    DateRanking = 1
© www.soinside.com 2019 - 2024. All rights reserved.