我对SQLite的changes()
函数有疑问,根据documentation,返回最近完成的INSERT更改或插入或删除的数据库行数, DELETE或UPDATE语句“(另请参阅documentation of the underlying C/C++ function)。
我希望使用此函数来检查执行与单行有关的UPDATE
语句确实是否导致该行被更改。
通过更改,我不仅仅意味着该行与语句的WHERE
子句匹配。不,我的意思是,对于有问题的行,执行后至少1列的值实际上是不同与之前相比。如果你问我这是在这种情况下更改的唯一正确定义。
所以我希望通过检查changes()
返回1
(行更改)或0
(行未更改)后立即调用来检测此类更改执行UPDATE
语句。
但令我绝望的是,这似乎没有按预期发挥作用。
请允许我说明一下:
CREATE TABLE People (Id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL);
INSERT INTO People (Name) VALUES ("Astrid");
SELECT changes();
此处changes()
按预期返回1
,因为我们只是INSERT
第1行。
UPDATE People SET Name = "Emma" WHERE Id = 1;
SELECT changes();
此处changes()
按预期返回1
,因为1行为UPDATE
d(即实际已更改:Name
Person
1}} Id = 1
为"Astrid"
,但现在为"Emma"
)。
UPDATE People SET Name = "John" WHERE Id = 200;
SELECT changes();
此处changes()
按预期返回0
,因为没有Id = 200
行。
到目前为止一切顺利。但是现在看看下面的UPDATE
语句,其中确实与现有行匹配,但 实际上更改它完全(Name
仍然设置为"Emma"
)...
UPDATE People SET Name = "Emma" WHERE Id = 1;
SELECT changes();
此处changes()
返回1
,而我当然希望0
: - (。
如果函数被称为matched_rows()
或affected_rows()
,那么这可能是有意义的。但对于一个名为changes()
的函数,并记录在案,这种行为让我觉得不合逻辑,或充其量令人困惑。
所以,无论如何,有人可以解释为什么会发生这种情况,或者甚至更好地提出一种替代策略,以可靠(高效)的方式实现我的目标吗?
我能想到的只是实际执行SELECT * FROM People WHERE Id = x
之类的操作,将所有返回的列值与我将要在UPDATE
语句中设置的值进行比较,从而决定是否需要执行完全是UPDATE
。但这不是很有效,对吧?
当然在这个玩具示例中它可能并不重要,但在我的实际应用程序中,我正在处理具有更多列的表,其中一些列(可能很大)BLOB
s。
答案 0 :(得分:9)
数据库不比较旧值和新值;任何UPDATEd行始终计为"已更改"即使价值恰好相同。 documentation表示
UPDATE会影响那些将WHERE子句表达式作为布尔表达式求值的结果为真的行。
如果要检查旧值,则必须明确地执行此操作:
UPDATE People SET Name = 'Emma' WHERE Id = 1 AND Name IS NOT 'Emma';