【问题标题】:Creating an update trigger to update a column in table1 based on a value in table2创建更新触发器以根据 table2 中的值更新 table1 中的列
【发布时间】:2018-05-08 20:32:36
【问题描述】:

在本帖底部更新


我在 SQL Server 中有两个表,下面是每个表的简化视图。

表 1

| ObjectID | Name | Email |
+----------+------+-------+
| 1        | Ben  |       |
| 2        | Tom  |       |

表2

| ObjectID  | Name |     Email     |
+-----------+------+---------------+
| 52        | Ben  | ben@email.com |
| 53        | Tom  | tom@email.com |

我想在更新 table1 的数据库中创建一个触发器,当我更新 name 字段时触发器会触发,并插入可以在 table2 中找到的电子邮件地址。

注意:两个表都有更多的列

注意2:当将一行插入表1时,它只接收一个ObjectID,然后在用户添加名称的地方进行更新。

用户添加此名称后,我希望数据库运行并查看table2,找到匹配的名称,然后返回table1并将数据写入其中。

我已经(不成功)编写了以下代码,我尝试过使用update() 和一堆其他东西,但我觉得我离题了:

CREATE TRIGGER "acc_insert_email" 
ON TABLE1
AFTER UPDATE
AS
BEGIN
    INSERT INTO TABLE1(email)
        SELECT i.email 
        FROM TABLE1 t 
        INNER JOIN TABLE2 i ON t.email = i.email
END

谁能指出我正确的方向?

提前致谢。


所以我已经测试了@Ezlo 提供的答案,但没有任何运气......我稍微修改了它,改为在列中插入单词 TEST,看看它是否会这样做,但这也没有影响。这是我目前拥有的代码,请注意我使用了实际的表名和列名:

CREATE TRIGGER "gisadmin"."acc_UpdateOfficerDetails" ON NOXIOUS_WEED_INSPECTION_POINT AFTER UPDATE
AS
BEGIN

    IF UPDATE(authorised_officer_email)
    BEGIN

        UPDATE T SET
            authorised_officer_email = 'TEST'
        FROM
            inserted AS I
            INNER JOIN NOXIOUS_WEED_INSPECTION_POINT AS T ON I.authorised_officer = T.authorised_officer
            LEFT JOIN AUTH_DB.authlive.dbo.acc_weave_emp_details AS N ON I.authorised_officer = N.cus_idd

    END
END

authorised_officercus_idd 是员工用户名(我已经成功地对这两个字段进行了简单的连接,它工作正常,所以我已经排除了两种不同的数据类型的问题)

所以我很困惑为什么这个触发器甚至没有为我插入简单的“测试”文本。

有什么想法吗?


下面是回答我最初问题的最终代码,效果很好!谢谢@EzLo

CREATE TRIGGER "gisadmin"."acc_UpdateOfficerDetails" ON NOXIOUS_WEED_INSPECTION_POINT AFTER
UPDATE AS BEGIN IF
UPDATE
    (authorised_officer) BEGIN
UPDATE
    T
SET
    authorised_officer_email = A.mto_lst
FROM
    inserted AS I
INNER JOIN
    NOXIOUS_WEED_INSPECTION_POINT AS T
ON
    I.authorised_officer = T.authorised_officer
LEFT JOIN
    AUTH_DB.authlive.dbo.acc_weave_emp_details AS A
ON
    I.authorised_officer = A.cus_idd
END
END

【问题讨论】:

  • 为什么要创建触发器。创建一个接受名称作为参数的存储过程。根据名字,从table2中获取对应的email地址,插入到table1中。除非在极少数情况下,否则通常应避免使用触发器。触发器使事务变得更长,并且难以调试和解决问题。
  • @VenkataramanR 非常感谢这个建议,我是后端数据库的新手,我会研究存储过程,看看是否足够:)
  • @VenkataramanR 存储过程可以在更新表行时运行吗?还是手动触发存储过程?
  • Storeprocedure 不在更新上运行,但将使用它在两个表中插入。
  • 但是,您的要求也可以使用触发器来完成。只需要校准工作流程。

标签: sql-server tsql database-trigger


【解决方案1】:

您可以使用以下内容。

CREATE TRIGGER tr_UpdateTable1Email ON TABLE1 AFTER UPDATE
AS
BEGIN

    IF UPDATE(Name)
    BEGIN

        UPDATE T SET
            Email = N.Email
        FROM
            inserted AS I
            INNER JOIN TABLE1 AS T ON I.Name = T.Name
            LEFT JOIN TABLE2 AS N ON I.Name = N.Name

    END
END

触发器将在 TABLE1 更新时执行,并且仅当原始更新语句包含 name 列时才会执行内部更新。 inserted 是一个特殊的触发器表,它保存更新的跟踪表(在本例中为TABLE1)的行。加入insertedTABLE1 以便能够更新正确的电子邮件,然后去搜索电子邮件以更新到TABLE2

让我提一下,您对数据进行了非规范化,这会导致维护问题(如果有人从 TABLE2 更新姓名或电子邮件会发生什么情况?TABLE1 的记录将不同步)。您应该只将姓名和电子邮件(以及其他相关数据)保存在 1 个位置,因此只需要更新一次。


编辑:更新超过 1 列(不需要括号)。

ALTER TRIGGER "gisadmin"."acc_UpdateOfficerDetails" ON NOXIOUS_WEED_INSPECTION_POINT AFTER UPDATE 
AS 
BEGIN 
    IF UPDATE (authorised_officer) 
    BEGIN

        UPDATE
            T
        SET
            authorised_officer_email = A.mto_lst,
            authorised_officer_phone = A.bus_mob
        FROM
            inserted AS I
        INNER JOIN
            NOXIOUS_WEED_INSPECTION_POINT AS T
        ON
            I.authorised_officer = T.authorised_officer
        LEFT JOIN
            AUTH_DB.authlive.dbo.acc_weave_emp_details AS A
        ON
            I.authorised_officer = A.cus_idd

    END
END

【讨论】:

  • 这看起来很有希望@EzLo,由于您的解释,我能够理解它在做什么,非常感谢。我现在已经从我的基本示例转换为匹配我的真实世界数据库,触发器是有效的并且在我创建它时不会引发错误。我刚刚通过更新几行员工姓名对其进行了测试,但我没有在我希望看到数据的列中看到任何数据,基本上我不确定触发器是否正在触发。有什么方法可以测试这个你知道吗?在 python 中我会插入打印语句,但 SQL 并不是那么简单。谢谢
  • @Benno 您可以将UPDATE T SET 部分切换为SELECT,因此如果它执行,那么您应该会看到来自触发器的结果集。确保在更新中从TABLE1 更新列Name,否则触发逻辑将不适用。您还应该从触发器内部的更新中看到类似于“(X 行受影响)”的消息(因此您将有 2 条消息,一条用于更新名称,另一条来自触发器,如果​​您没有SET NOCOUNT ON)。 编辑:您的 IF 似乎在错误的列上,应该是 authorised_officer,现在是 authorised_officer_email
  • 你一针见血,当机立断!谢谢。我刚刚将最终的工作代码放在我原来的帖子中。最后一个小问题,我可以使用一个触发器更新两个字段吗?还是我必须将它们分成两部分?我想添加修改这个SET authorised_officer_email = A.mto_lst 而不是SET (authorised_officer_email = A.mto_lst, authorised_officer_phone = A.bus_mob),但是当我尝试这个时,我得到以下错误:{0:0} Incorrect syntax near '('.,有没有办法正确地做到这一点?
  • @Benno 不需要括号更新,只需用逗号分隔每列即可。我用你的例子编辑了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
相关资源
最近更新 更多