【问题标题】:SQL field values not accurately updatedSQL 字段值未准确更新
【发布时间】:2015-10-01 02:14:50
【问题描述】:

如果记录被更新,它将被标记为 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)
)

【问题讨论】:

  • 我认为如果你指定你正在使用的表结构会很有帮助,因为现在我们不得不猜测它们。两个表的主键都是ID + CreationDate?
  • @eyeballs 您的编辑栏可能是多余的。您只能使用CreationDateModificationDate。所以没有更新的记录会有ModificationDate NULL。

标签: sql field


【解决方案1】:

您的触发器中的UPDATE 没有过滤任何内容,因此它将遍历由返回的所有行

FROM ProcessList
INNER JOIN ProcessListHist ON ProcessList.ID = ProcessListHist.ID

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

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加入,先得到修改的行,再加入历史表就可以得到新的修改日期。

但如果你注意了,你加入最后一个表只是为了得到你已经拥有的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

【讨论】:

  • 啊,是的,我确实需要 ModificationDate 字段,因为我的数据库允许用户将 excel 文件导入其中,因此如果他们在数据库之外编辑某些内容,它会显示。我的数据库现在按我想要的方式工作。非常感谢您的时间和帮助! :> @安德鲁
【解决方案2】:

我看不出有什么理由让你的生活变得如此复杂,因为你现在的使用方式如此复杂。

让我们一一理解。您具有以下表结构,并且您有两个操作,即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 的情况下,Edit 将为空(这本身就是一个设计缺陷,稍后将讨论),ID-Name-Amount-CreationDate 将有一个值,而 ModificationDate 将再次为 NULL。这是一个简单的用例。

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

更新/编辑

如果是 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

【讨论】:

  • 感谢指出缺陷部分!将在我的数据库中实现它:> 非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多