如何在 SQLite 的单个语句中从多个不相关的表中删除?
How to delete from multiple unrelated tables in single statement in SQLite?
我需要实现一个功能,该功能可以简单地清除数据库中除少数表格之外的所有数据。考虑到到目前为止代码的编写方式,这样做比实现一个实际删除整个数据库文件并创建一个新文件的外部函数要容易得多。
我想在 一个 准备好的语句上执行此操作,这样我就可以通过使用多个语句并按顺序执行它们来避免代码膨胀。为了以防万一,我还想使用 begin
和 commit
在单个事务中执行此操作。我试过的是:
begin;
DELETE FROM dataTable;
DELETE FROM cacheTable;
DELETE FROM someOtherTable;
commit;
运行 在 DBeaver 中,这不仅不起作用,而且实际上它以某种方式使数据库保持打开状态,从我第二次尝试的错误判断:
SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (cannot start a transaction within a transaction)
我相信发生的事情只是第一行被执行,分号后的所有内容都被忽略。
这可以在一条语句中完成吗?
I want to do this on one prepared statement, so that I can avoid code bloat by having multiple statements and executing them in sequence.
每个都必须是单个语句(除非 ..)。
但是,如果您想通过单个语句执行操作,那么虽然有点复杂,但您可以使用 TRIGGER,它可以在单个事务中执行多个语句(有限制)。
I would also like to do it in a single transaction using begin and commit just in case.
如果您使用单个语句,那么它始终是单个事务,不需要 BEGIN .... COMMIT。
如果您走 TRIGGER 路线,那么这里是 example/demo。
- 需要触发 TRIGGER,因此您可以专门为此使用 table(使用其他 table 可能会导致意外触发)。
- 下面的example/demo使用了这样一个table即triggerTable。
- 它通常为空(与其他 table 一起被触发器清除)。
- 由于 TRIGGER 是一个 AFTER INSERT 触发器(根据演示),在 triggerTable 中插入一行会启动其他 table 的清除,并且触发表。
- 应该有最小的开销,插入行的实际插入和后续删除的时间很少,可能只有 table.
的 1(4k 额外存储)页面
也许可以考虑以下 example/demo :-
/* Prepare Testing Environment */
CREATE TABLE IF NOT EXISTS dataTable (x);
CREATE TABLE IF NOT EXISTS cacheTable (y);
CREATE TABLE IF NOT EXISTS someOtherTable(z);
/* triggerTable could be another table */
CREATE TABLE IF NOT EXISTS triggerTable(id INTEGER PRIMARY KEY);
DROP TRIGGER IF EXISTS trigger_deletions;
/* The Trigger that will do the deletions in a single transaction */
CREATE TRIGGER IF NOT EXISTS trigger_deleteions AFTER INSERT ON triggerTable
BEGIN
DELETE FROM dataTable;
DELETE FROM cacheTable;
DELETE FROM someOtherTable;
DELETE FROM triggerTable; /* if triggerTable used */
END
;
/* Load some data */
INSERT INTO dataTable VALUES (1),(2),(3);
INSERT INTO cacheTable VALUES (1),(2),(3);
INSERT INTO someOtherTable VALUES (1),(2),(3);
/* Show the before test data PLUS trailer just in case nothing selected */
SELECT 'DT',* FROM dataTable UNION ALL SELECT 'CT',* FROM cacheTable UNION ALL SELECT 'SOT',* FROM someOtherTable UNION ALL SELECT 'trailer','trailer';
/* Initiate the Deletions */
INSERT INTO triggerTable VALUES(1);
/* Show the after test data PLUS trailer just as no data to select */
SELECT 'DT',* FROM dataTable UNION ALL SELECT 'CT',* FROM cacheTable UNION ALL SELECT 'SOT',* FROM someOtherTable UNION ALL SELECT 'trailer','trailer';
/* show the state of the trigger table */
SELECT * FROM triggerTable;
/* CleanUp Testing Environment */
DROP TABLE IF EXISTS dataTable;
DROP TABLE IF EXISTS cacheTable;
DROP TABLE IF EXISTS someOtherTable;
Running this in DBeaver, not only it does not work, it actually somehow leaves the database with the transaction still open, judging from this error that I get on a second try:
您是否正在执行脚本 as opposed to executing a statement ?
使用 DBeaver 使用上述结果:-
我需要实现一个功能,该功能可以简单地清除数据库中除少数表格之外的所有数据。考虑到到目前为止代码的编写方式,这样做比实现一个实际删除整个数据库文件并创建一个新文件的外部函数要容易得多。
我想在 一个 准备好的语句上执行此操作,这样我就可以通过使用多个语句并按顺序执行它们来避免代码膨胀。为了以防万一,我还想使用 begin
和 commit
在单个事务中执行此操作。我试过的是:
begin;
DELETE FROM dataTable;
DELETE FROM cacheTable;
DELETE FROM someOtherTable;
commit;
运行 在 DBeaver 中,这不仅不起作用,而且实际上它以某种方式使数据库保持打开状态,从我第二次尝试的错误判断:
SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (cannot start a transaction within a transaction)
我相信发生的事情只是第一行被执行,分号后的所有内容都被忽略。
这可以在一条语句中完成吗?
I want to do this on one prepared statement, so that I can avoid code bloat by having multiple statements and executing them in sequence.
每个都必须是单个语句(除非 ..)。
但是,如果您想通过单个语句执行操作,那么虽然有点复杂,但您可以使用 TRIGGER,它可以在单个事务中执行多个语句(有限制)。
I would also like to do it in a single transaction using begin and commit just in case.
如果您使用单个语句,那么它始终是单个事务,不需要 BEGIN .... COMMIT。
如果您走 TRIGGER 路线,那么这里是 example/demo。
- 需要触发 TRIGGER,因此您可以专门为此使用 table(使用其他 table 可能会导致意外触发)。
- 下面的example/demo使用了这样一个table即triggerTable。
- 它通常为空(与其他 table 一起被触发器清除)。
- 由于 TRIGGER 是一个 AFTER INSERT 触发器(根据演示),在 triggerTable 中插入一行会启动其他 table 的清除,并且触发表。
- 应该有最小的开销,插入行的实际插入和后续删除的时间很少,可能只有 table. 的 1(4k 额外存储)页面
也许可以考虑以下 example/demo :-
/* Prepare Testing Environment */
CREATE TABLE IF NOT EXISTS dataTable (x);
CREATE TABLE IF NOT EXISTS cacheTable (y);
CREATE TABLE IF NOT EXISTS someOtherTable(z);
/* triggerTable could be another table */
CREATE TABLE IF NOT EXISTS triggerTable(id INTEGER PRIMARY KEY);
DROP TRIGGER IF EXISTS trigger_deletions;
/* The Trigger that will do the deletions in a single transaction */
CREATE TRIGGER IF NOT EXISTS trigger_deleteions AFTER INSERT ON triggerTable
BEGIN
DELETE FROM dataTable;
DELETE FROM cacheTable;
DELETE FROM someOtherTable;
DELETE FROM triggerTable; /* if triggerTable used */
END
;
/* Load some data */
INSERT INTO dataTable VALUES (1),(2),(3);
INSERT INTO cacheTable VALUES (1),(2),(3);
INSERT INTO someOtherTable VALUES (1),(2),(3);
/* Show the before test data PLUS trailer just in case nothing selected */
SELECT 'DT',* FROM dataTable UNION ALL SELECT 'CT',* FROM cacheTable UNION ALL SELECT 'SOT',* FROM someOtherTable UNION ALL SELECT 'trailer','trailer';
/* Initiate the Deletions */
INSERT INTO triggerTable VALUES(1);
/* Show the after test data PLUS trailer just as no data to select */
SELECT 'DT',* FROM dataTable UNION ALL SELECT 'CT',* FROM cacheTable UNION ALL SELECT 'SOT',* FROM someOtherTable UNION ALL SELECT 'trailer','trailer';
/* show the state of the trigger table */
SELECT * FROM triggerTable;
/* CleanUp Testing Environment */
DROP TABLE IF EXISTS dataTable;
DROP TABLE IF EXISTS cacheTable;
DROP TABLE IF EXISTS someOtherTable;
Running this in DBeaver, not only it does not work, it actually somehow leaves the database with the transaction still open, judging from this error that I get on a second try:
您是否正在执行脚本
使用 DBeaver 使用上述结果:-