我现在使用sqldiff工具计算事务执行之前和执行之后数据库之间的差异。我这样做是为了:
将整个sqlite文件复制到tmp位置(old database.sqlite)
执行事务(例如插入、架构更改等)
Than sqldiff——主键old-database.sqlite database.sqlite
这将输出事务所做的更改。虽然这很好,因为我的数据库不是那么大,最大几兆字节。我认为这样做会更有效率。
有没有什么机制可以用来在不复制数据库的情况下获得相同的输出。也许是日记上的事?
谨致问候,
大安
最佳答案
也许实现起来有点笨拙,也许在某个阶段(按大小)效率低下,但是您可以使用触发器(每个被监视的表4个是笨拙的部分)和sqlite_master的前后快照的组合。
也就是说,对于每个要监视的表,可以将该表的副本(按结构)附加两列。1表示操作(在更新前、更新或删除后插入),第2个(可选)表示记录时间戳。
然后,对于要监视的每个表,have AFTER INSERT、BEFORE DELETE和AFTER及BEFORE UPDATE触发器将add an条目复制到表的日志表中,该日志表将在事务之前清空(如果需要,如果不需要,则timestamp可能是必需的列)。
对于架构更改,您可以在之前拥有一个sqlite_master的副本,然后在事务之后将其与sqlite_master进行比较(不能将触发器应用于系统表)。
例如,考虑以下示例/演示:-
CREATE TABLE IF NOT EXISTS mytable (id INTEGER PRIMARY KEY, mycolumn TEXT);
CREATE TABLE IF NOT EXISTS mytablelog AS SELECT * FROM mytable WHERE 0 = 1;
ALTER TABLE mytablelog ADD COLUMN logtype INTEGER;
ALTER TABLE mytablelog ADD COLUMN timestamp INTEGER TEXT;
CREATE TABLE IF NOT EXISTS schema_log AS SELECT * FROM sqlite_master WHERE 0=1;
CREATE TABLE IF NOT EXISTS pretrans_schema AS SELECT * FROM sqlite_master WHERE 0=1;
ALTER TABLE schema_log ADD COLUMN logtype INTEGER;
ALTER TABLE schema_log ADD COLUMN timestamp INTEGER TEXT;
CREATE TRIGGER IF NOT EXISTS mytable_inserts AFTER INSERT ON mytable
BEGIN
INSERT INTO mytablelog SELECT *,0,strftime('%s','now') FROM mytable WHERE id = new.id;
END
;
CREATE TRIGGER IF NOT EXISTS mytable_deletions BEFORE DELETE ON mytable
BEGIN
INSERT INTO mytablelog SELECT *,1,strftime('%s','now') FROM mytable WHERE id = old.id;
END
;
CREATE TRIGGER IF NOT EXISTS mytable_preupdates BEFORE UPDATE ON mytable
BEGIN
INSERT INTO mytablelog SELECT *,2,strftime('%s','now') FROM mytable WHERE id = old.id;
END
;
CREATE TRIGGER IF NOT EXISTS mytable_postupdates AFTER UPDATE ON mytable
BEGIN
INSERT INTO mytablelog SELECT *,3,strftime('%s','now') FROM mytable WHERE id = new.id;
END
;
-- SELECT * FROM sqlite_master WHERE name LIKE 'sqlite_%';
/* BEFORE TRANSACTION PREPATION */
DELETE FROM mytablelog;
DELETE FROM schema_log;
DELETE FROM pretrans_schema;
INSERT INTO pretrans_schema SELECT * FROM sqlite_master;
/* DO SOMETHING AKA THE TRANSACTIONS */
CREATE TABLE IF NOT EXISTS newtable (id INTEGER PRIMARY KEY, acolumn TEXT);
INSERT INTO mytable (mycolumn) VALUES ('Mary')
-- ,('Fred'),('Jane'),('Anne'),('Alfred'),('George'),('Alan')
,('Susan'),('Betty'),('Catherine'),('John')
,(100),(200)
;
UPDATE mytable SET mycolumn = mycolumn||' has the detected letter.' WHERE mycolumn LIKE '%n%';
DELETE FROM mytable WHERE CAST(mycolumn AS INTEGER) > 0;
/* AFTER TRANSACTION */
SELECT rowid,'sm',* FROM sqlite_master UNION ALL SELECT rowid,'pt',* FROM pretrans_schema ORDER BY type,name; /* FOR DEMO/TESTING */
/* Get items added to the schema */
INSERT INTO schema_log SELECT *,4,strftime('%s','now') FROM sqlite_master WHERE name NOT IN (SELECT name FROM pretrans_schema);
/* Get items deleted from the schema */
INSERT INTO schema_log SELECT *,5,strftime('%s','now') FROM pretrans_schema WHERE name NOT IN (SELECT name FROM sqlite_master);
/* get original schema if schema updates */
INSERT INTO schema_log SELECT *,6,strftime('%s','now') FROM sqlite_master AS s
WHERE (sql <> (SELECT sql FROM pretrans_schema WHERE type = s.type AND name = s.name )) AND type IS NOT NULL /* AND NAME <> 'pretrans_schema' optional */
;
/* get current schema if schema updates */
INSERT INTO schema_log SELECT *,7,strftime('%s','now') FROM pretrans_schema AS s
WHERE (sql <> (SELECT sql FROM sqlite_master WHERE type = s.type AND name = s.name)) AND type IS NOT NULL /* AND NAME <> 'pretrans_schema' */
;
SELECT * FROM schema_log;
SELECT * FROM mytablelog;
结果
1前后模式(部分)
请注意突出显示的行,没有pt条目,表示表已添加(没有sm条目则会被删除)。
2-架构更改日志(架构日志表)
4表示架构中的新项(删除5个,更新前6个,更新后7个)
因此,表newtable已作为事务的一部分添加。
3-mytable事务;
O是插入,1分别在更新前和更新后删除2和3(成对)。
关于c - 交易前后的差异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58439253/