【问题标题】:SQLite trigger insert/replace multiple rows multiple tablesSQLite 触发器插入/替换多行多表
【发布时间】:2013-10-30 23:22:38
【问题描述】:

我正在尝试响应在一个表 (A) 中插入一行,以根据第三个表 (C) 的值创建或更新第二个表 (B) 中的多行(可以连接到第一个)。

我有以下构造,

CREATE TRIGGER MyTrigger AFTER INSERT ON A
    BEGIN
        INSERT OR REPLACE INTO B (ID, T1, T2, Role)
        VALUES
        (
            ( SELECT ID FROM C WHERE R1 = NEW.R1 ),
            NEW.T1,
            B.T2, -- The existing row's T2
            ( SELECT Role FROM C WHERE R1 = NEW.R1 ),
        )
    END;

Table A has columns ID, T1, R1
Table B has columns ID, T1, T2, Role
Table C has columns ID, R1, R2, Role

我在尝试编写触发器时至少有两个问题

  1. 我不知道如何在 REPLACE 案例中引用 B 的现有值,因此是“B.T2”
  2. 在表 B 中执行 INSERT/REPLACE 时,我不知道如何从表 C 的同一行中引用多个列(R1、角色)。

感谢您为解决此问题提供的任何帮助。

【问题讨论】:

  • 使用SELECT ... FROM B WHERE ROWID=NEW.ROWID 而不是VALUES(...)
  • 你最好写一个答案并接受它!只是为了避免保留未解决的问题。

标签: sqlite triggers


【解决方案1】:

使用SELECT 代替VALUES

CREATE TRIGGER MyTrigger AFTER INSERT ON A BEGIN
    INSERT OR REPLACE INTO B (ID, T1, T2, Role) SELECT
        (SELECT ID FROM C WHERE R1 = NEW.R1),
        NEW.T1,
        B.T2,
        (SELECT Role FROM C WHERE R1 = NEW.R1)
        FROM B WHERE ROWID=NEW.ROWID
    END;

【讨论】:

  • 鉴于 NEW 指的是 A 中的一行,“FROM B WHERE ROWID=NEW.ROWID”不是注定要失败吗?在任何情况下,我都无法使 SELECT 以这种形式工作,包括尝试选择常量值。使用 VALUES 表单直接插入常量的触发器工作正常,但这只能验证我的测试台。我仍然被列出的两个问题所困扰。
  • 为什么B.rowid 应该和A.rowid 一样?而对于新插入的A 记录,NEW.rowid 将永远不会在B 中找到,因此外部 SELECT 不会返回任何内容。
【解决方案2】:

我能够在 SELECT 上使用 LEFT OUTER JOIN,这样无论是否存在现有行,都可以命名所有需要的值。

CREATE TRIGGER MyTrigger AFTER INSERT ON A
    BEGIN
        INSERT OR REPLACE INTO B (ID, T1, T2, Role)
            SELECT
                C.ID,
                NEW.T1,
                B.T2,
                C.Role
            FROM C LEFT OUTER JOIN B ON C.ID = B.ID WHERE C.R1 = NEW.R1;
    END;

【讨论】:

    【解决方案3】:

    要查找B 记录,只需像使用C 一样使用子查询。 要搜索的 B.ID 值与您尝试插入的值相同。

    CREATE TRIGGER MyTrigger
    AFTER INSERT ON A
    BEGIN
        INSERT OR REPLACE INTO B (ID, T1, T2, Role)
        VALUES
        (
            ( SELECT ID FROM C WHERE R1 = NEW.R1 ),
            NEW.T1,
            ( SELECT T2 FROM B WHERE ID = ( SELECT ID FROM C WHERE R1 = NEW.R1 ) ),
            ( SELECT Role FROM C WHERE R1 = NEW.R1 )
        );
    END;
    

    【讨论】:

    • 这是朝着正确方向迈出的一步,给了我一张形状正确的单一唱片。现在我的挑战是能够处理表 C 中涉及多行的情况 - 我的触发器涉及的第二个问题。也就是说,我的测试用例在 C 中有两行,其中 R1 = NEW.R1。现在,我只在 B 中为 C 中的第一行插入一行。这很有意义,因为内部 SELECT 只应该提供一个值。所以我假设 SQLite 正在获取返回的第一个值。
    猜你喜欢
    • 2023-03-08
    • 2012-11-25
    • 2014-06-19
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多