SQL 字段值未准确更新

SQL field values not accurately updated

如果记录有更新,则用Y标记,最新版本用null标记。最新更新记录的 CreationDate 应取自先前记录的 ModificationDate。但如屏幕截图所示,该字段未正确更新。有谁知道如何解决这个错误?

如果CreationDate字段值准确,则记录应该是序号。 6, 8, 7

CREATE TRIGGER CloneAfterUpdate ON ProcessList
AFTER UPDATE
AS
IF (UPDATE (Amount) OR UPDATE (NAME))
BEGIN
    INSERT INTO ProcessListHist (
        ID
        ,NAME
        ,Amount
        ,CreationDate
        ,Edited
        ,ModificationDate
        )
    SELECT ID
        ,NAME
        ,Amount
        ,CreationDate
        ,'Y'
        ,GETDATE()
    FROM deleted

    UPDATE ProcessList
    SET ProcessList.CreationDate = ProcessListHist.ModificationDate
    FROM ProcessList
    INNER JOIN ProcessListHist ON ProcessList.ID = ProcessListHist.ID
END

UPDATE ProcessList
SET Amount = 9800
WHERE NAME = 'Rachel'

SELECT *
FROM ProcessList

UNION ALL

SELECT *
FROM ProcessListHist
ORDER BY ID ASC ,CreationDate ASC

---更新了---

CREATE TABLE dbo.ProcessList
(
    Edited              varchar(1),
    ID                  integer         NOT NULL,
    Name                varchar(30)     NOT NULL,
    Amount              smallmoney      NOT NULL,
    CreationDate        datetime        DEFAULT GETDATE(),
    ModificationDate    datetime,
    PRIMARY KEY (ID, CreationDate)
)


CREATE TABLE dbo.ProcessListHist
(
    Edited              varchar(1),
    ID                  integer         NOT NULL,
    Name                varchar(30)     NOT NULL,
    Amount              smallmoney      NOT NULL,
    CreationDate        datetime        NOT NULL,
    ModificationDate    datetime,
    PRIMARY KEY (ID, CreationDate)
)

触发器中的 UPDATE 未过滤任何内容,因此它将遍历

返回的所有行
FROM ProcessList
INNER JOIN ProcessListHist ON ProcessList.ID = ProcessListHist.ID

并将每个 ModificationDate 分配给 ProcessList table,每次都会覆盖先前的值,因此您最终会得到最后一个,无论它是什么。只需要获取修改行的数据,所以需要加入deletetable,像这样:

UPDATE PL
SET PL.CreationDate = PLH.ModificationDate
FROM ProcessList PL
INNER JOIN deleted on PL.ID = deleted.ID AND PL.CreationDate = deleted.CreationDate
INNER JOIN ProcessListHist PLH ON PL.ID = PLH.ID AND PLH.CreationDate = deleted.CreationDate

通过加入delete,先得到修改行,然后加入历史table得到新的修改日期

但是如果你注意的话,你加入最后一个table只是为了得到你已经拥有的datetime(当你调用GETDATE时),所以你可以简化触发器有点像这样:

DECLARE @Now DATETIME
SELECT @Now = GETDATE()
INSERT INTO ProcessListHist (
    ID
    ,NAME
    ,Amount
    ,CreationDate
    ,Edited
    ,ModificationDate
    )
SELECT ID
    ,NAME
    ,Amount
    ,CreationDate
    ,'Y'
    ,@Now
FROM deleted

UPDATE PL
SET PL.CreationDate = @Now
FROM ProcessList PL
INNER JOIN deleted on PL.ID = deleted.ID AND PL.CreationDate = deleted.CreationDate

ProcessList 是否需要 ModificationDate 字段?为什么需要 Edited 字段?据我所知,一个总是NULL,另一个总是Y。如果将它们全部删除,则可以像这样执行最后一个查询:

SELECT NULL AS Edited, ID, Name, Amount, CreationDate, NULL AS ModificationDate
FROM ProcessList

UNION ALL

SELECT 'Y', ID, Name, Amount, CreationDate, ModificationDate
FROM ProcessListHist
ORDER BY ID ASC ,CreationDate ASC

我看不出有任何理由让您的生活因您当前使用的方式而变得如此复杂。

让我们一一了解。你有以下 table 结构,你有两个操作,即 InsertDelete.

CREATE TABLE dbo.ProcessList
(
    Edited              varchar(1),
    ID                  integer         NOT NULL,
    Name                varchar(30)     NOT NULL,
    Amount              smallmoney      NOT NULL,
    CreationDate        datetime        DEFAULT GETDATE(),
    ModificationDate    datetime,
    PRIMARY KEY (ID, CreationDate)
)

Insert

如果是 INSERT,Edit 将为空(这本身就是一个设计缺陷,稍后讨论),ID-Name-Amount-CreationDate 将有一个值,而 ModificationDate 将再次为 NULL。这是一个简单的用例。

Insert into YouTableName values (null,4035,'Rachel Zane',1000,getdate(),null)

Update/Edit

如果是 EDIT,您需要将 EDIT 列更新​​为 'Y',您将更新其余字段,只需将 ModificationDate 复制到 CreationDate,如下所示

Update table
set Edit = 'Y',
Name = <NewNameIfAny>,
Amount = <NewAmountIfAny>,
CreationDate = ModificationDate,
ModificationDate = Getdate()

就是这样,你就完成了,这样你就不需要任何 Trigger。而且我没有看到任何相同的用例。您可以阅读 here 使用触发器的用例。

DesignFlaw:当您知道您将在 EDIT 列中成为 'Y' 或 'null' 时,为什么不成功bit 类型,比任何东西都快。比特将作为你的旗帜。最初您可以将其标记为 False (0),并且每当发生任何编辑时,将其更新为 True (1)。而已。您可以将列重命名为 IsEdited.