【问题标题】:SQL Server trigger for comparing old values with new values before insert用于在插入之前将旧值与新值进行比较的 SQL Server 触发器
【发布时间】:2016-05-05 09:21:15
【问题描述】:

我在 SQL Server 中创建触发器时遇到问题,因为我不清楚如何用旧值检查新值。

我有一个名为 MTRL 的主表和另一个名为 CCCMTRL 的主表。我想在对 MTRL 表进行更新之前从 MTRL 表中选择列 MTRL(MTRL 表的主键)、COMPANY 和 PRICE,并激活一个触发器,该触发器必须将 MTRL 的新价格与 CCCMTRL 的旧价格进行比较。

如果价格相同,则无需更新,但如果价格不同,则应在 CCCMTRL 中插入

INSERT INTO CCCMTRL(MTRL,COMPANY,OLDPRICE,NEWPRICE) 
VALUES (MTRL,COMPANY,OLD.PRICE,NEW.PRICE)

类似的东西。

【问题讨论】:

  • 你能发布MTRLCCCMTRL 的表架构吗?
  • "如果价格相同,则无需更新" ...或者您只需继续更新,因为没有任何变化。 “但如果它们不同,则应该在 CCCMTRL 中插入”,这可以通过触发器来实现。
  • 我无法发布架构,因为主表很大,它有超过 100 列...
  • 老实说...您是否尝试过基本搜索?这个怎么样? stackoverflow.com/questions/15228670/…

标签: sql-server triggers


【解决方案1】:

我想弄清楚您为什么要经历处理触发器的麻烦。只需重新格式化您的插入,以便它自动处理您的状况。

我必须假设 CCCMTRL 表中还有一些其他字段,其中一个是价格日期变化,因为您没有提供价格总是上涨或下跌的条件,所以我 假设这是由某种日期字段跟踪的,我在下面的示例查询中将其称为 DATEFIELD。

基本上,此查询将识别 *new *price 是否不再匹配 CCCMTRL 表中最近的 old 价格(排序由 ROW_NUMBER() 窗口函数执行)。如果您有任何不匹配,它们将被插入到 CCCMTRL 表中:

--Optionally insert DATEFIELD if this is not tracked via default constraint
INSERT INTO CCCMTRL(MTRL,COMPANY,OLDPRICE,NEWPRICE)
SELECT 
    t_window.MTRL, 
    t_window.COMPANY, 
    t_window.OLD_PRICE, 
    t_window.NEW_PRICE
FROM (
    SELECT 
        MTRL, 
        COMPANY, 
        OLD.PRICE AS OLD_PRICE, 
        NEW.PRICE AS NEW_PRICE, 
        ROW_NUMBER() (PARTITION BY OLD.MTRL, OLD.COMPANY ORDER BY OLD.DATEFIELD DESC) AS RowNum
    FROM CCCMTRL OLD LEFT OUTER JOIN CCCMTRL_NEW NEW
        ON  OLD.MTRL = NEW.MTRL
        AND OLD.COMPANY = NEW.COMPANY
    WHERE OLD.PRICE <> NEW.PRICE
) t_window
WHERE RowNum = 1

下面是一个快速示例查询,它通过一个工作示例有效地展示了我所说的内容。希望这可以解决您的问题,而不会使您的数据库与触发器混淆。

SELECT COL1, COL2, DT
FROM 
(
    SELECT COL1, COL2, DT, 
    -- Create Windows Based On Colums and Assign Number based on Age of records
    ROW_NUMBER() OVER (PARTITION BY COL1, COL2 ORDER BY DT DESC) AS RowNum
    FROM
    (
        -- Row will be filtered out as it's the oldest of Liquids/Blues
        SELECT 'Liquid' AS COL1, 'Blue' AS COL2, GETDATE() - 1 AS DT
        UNION
        SELECT 'Liquid', 'Blue', GETDATE()
        UNION
        SELECT 'Liquid', 'Red', GETDATE()
        UNION
        -- Row will be filtered out as it's the oldest of Solid/Greens
        SELECT 'Solid', 'Green', GETDATE()
        UNION
        SELECT 'Solid', 'Green', GETDATE() + 2
    ) t_example
) t_windowed
WHERE RowNum = 1

【讨论】:

    【解决方案2】:

    这可以使用 INSTEAD OF INSERT TRIGGER 来实现。

    1. 在表格顶部创建视图

    2. 在视图顶部创建 INSTEAD OF INSERT 触发器。

      更多详情请见网址

    https://technet.microsoft.com/en-us/library/ms175521%28v=sql.105%29.aspx

    【讨论】:

    • 我纠正了一个错字,但老实说,您应该将相关信息复制到此页面并包含文章的链接。虽然 microsoft.com 仍然存在,但链接一直在移动,建议在 Stack 的网络上进行练习。
    【解决方案3】:

    用于在插入之前将旧值与新值进行比较的 SQL Server 触发器

    不可能。 SQL Server 101,在文档中清晰可读:没有插入前触发器。

    您只有一个 on insert(AFTER insert)和 INSTEAD OF(这意味着没有 insert,但您可以在检查后在触发器中执行 insert)。

    在您的情况下,插入后触发器也可以工作。

    【讨论】:

    • 这并不能真正回答问题。如果您解释 为什么如何 在您的情况下,插入后触发器也可以工作,您的答案可能会更好。说明如何以适用于 OP 的方式使用触发器
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    相关资源
    最近更新 更多