我试图将更新记录到SQLite表中的字段中。我已经能够使用以下内容登录INSERTs:
CREATE TRIGGER _test7_INSERT AFTER INSERT ON test7
BEGIN
INSERT INTO ChangeLog (rid, field, value, tms)
SELECT *,CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER)
FROM (VALUES
(new.rowid, 'field1', new.field1),
(new.rowid, 'field2', new.field2),
(new.rowid, 'field3', new.field3)
) sub;
END;
这显然是使用匿名值,我无法找到具体的文档,但它似乎可以创建一个静态表,然后我可以选择将其插入到日志表中。
但是,对于更新,我只想记录实际更改的字段,因此,例如,如果一个表有20个字段,并且由于更新而只更改了1个,那么我只希望将1行添加到更改表中,而不是20行。我有一个触发器,看起来像这样:
CREATE TRIGGER _test7_UPDATE AFTER UPDATE on test7
BEGIN
INSERT INTO ChangeLog (rid, field, value, tms)
SELECT "" AS rid,
":1" AS field,
":2" AS value,
CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER) AS tms
FROM (VALUES
(old.rowid, 'field1', new.field1, new.field1=old.field1),
(old.rowid, 'field2', new.field2, new.field2=old.field2),
(old.rowid, 'field3', new.field3, new.field3=old.field3)
) sub
WHERE ":4"=1;
END;
但是在我做更新时没有插入任何内容!如果我删除额外的比较字段并删除" WHERE"子句,我看到添加了三行,但我没有添加rid
,field
和value
,而是看到字面值"",&#34 ;:1"和":2"。我还没有找到关于这些编号参数的大量文档 - "参数"下的SQLite language page。部分提到了他们,但提供的信息很少 - 实际上它甚至没有解释为什么":1"实际上是第二个参数和""是第一个!我应该补充一点,我已尝试在触发器之外使用非常相似的SELECT,在VALUES表中放置常量值,它完美运行!具体做法是:
SELECT "" AS a, ":1" AS b, ":2" AS c, ":3" AS d
FROM (VALUES
(11,22,33,44),
(111,122,133,144),
(211,222,233,244)
) sub;
返回一个包含文字值的表格,标有&#34的列;"," b"," c"和" d" 。但是触发器中的相同基本结构会返回带冒号的文字字符串,而不是实际的预期值。
我有一个明智的想法,即创建一个带有额外字段的临时表,选择所有内容,然后选择除真实日志表中的比较之外的所有内容。这不起作用,因为触发器不支持CREATE
我还尝试创建ChangeLog以在比较中有一个额外的字段来保存第五个字段(例如new.fieldx = old.fieldx)但是当我使用WHERE子句只选择更改的字段时,我又回到了没有再插入。
我还有其他方法可以解决这个问题,还是我在处理位置参数方面做错了什么?
更新:我一直在尝试,并发现在某些情况下,位置参数实际上有值,但它们相当荒谬:
具体来说,字段""
返回第二个参数的值,字段":1"
返回第四个参数的值。为什么?如何引用第一个和第三个参数?
更新2 :再多玩一遍后,看来"",":1",": 2"等参数工作正常,只要VALUES表中只有常量值。我插入的任何实际值,例如来自new,old等等 - 我实际需要的列 - 都被完全忽略,好像那些列甚至不存在!
答案 0 :(得分:0)
这应该有效:
CREATE TRIGGER _test7_UPDATE AFTER UPDATE on test7
BEGIN
INSERT INTO ChangeLog (rid, field, value, tms)
SELECT rowid, field, value,
CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER)
FROM (
SELECT 0 rowid, '' field, 0 value, 0 keep
UNION ALL
SELECT sub.* FROM (VALUES
(old.rowid, 'field1', new.field1, new.field1!=old.field1),
(old.rowid, 'field2', new.field2, new.field2!=old.field2),
(old.rowid, 'field3', new.field3, new.field3!=old.field3)
) AS sub
) WHERE keep=1;
END
诀窍是使用UNION ALL
将虚拟行中的字段名称绑定到后面的常量行,然后过滤掉虚拟行。