如何在 SQLite 中使用触发器为特定 table 设置最大项目?
How to set a max items for a specific table using Trigger, in SQLite?
这是一个简单的问题。
背景
根据时间戳字段,我应该在某些 table 中最多有 400 行,所以旧的将被自动删除。在这里,假设它是 3。
table 有多个字段,但时间戳在这里很重要。
问题
尽管我已经成功了(看起来 here),但出于某种原因,它让我最多只能添加一个项目,所以我只是相应地进行了调整。这意味着我得到了 4 件而不是 3 件。
private const val MAX_ITEMS = 3
private val TIMESTAMP_FIELD = "timestamp"
private val DELETE_FROM_CALL_LOG_TILL_TRIGGER =
String.format(
"CREATE TRIGGER %1$s INSERT ON %2$s
WHEN (select count(*) from %2$s)>%3$s
BEGIN
DELETE FROM %2$s WHERE %2$s._id IN " +
"(SELECT %2$s._id FROM %2$s ORDER BY %2$s.$TIMESTAMP_FIELD DESC LIMIT %3$d, -1);
END;"
, "delete_till_reached_max", TABLE_NAME, MAX_ITEMS - 1)
我试过的
我试过了:
- 将条件更改为仅插入(意味着没有
WHEN
部分)
- 将
LIMIT %3$d, -1
更改为 LIMIT -1 OFFSET %3$d
。还尝试了与“-1”不同的数字(尝试了 0,因为我认为它是额外的)。
问题
- 为什么我必须使用
MAX_ITEMS - 1
而不是 MAX_ITEMS
?为什么它给我留下了 4 个项目而不是 3 个?
- 如果我有
WHEN
有关系吗?好点了吗?
- 您省略了
BEFORE | AFTER
子句,因此默认为 BEFORE
。这意味着您计算的是插入 之前 的行数,而不是插入之后的行数。
- 这取决于。起初,当 table 还没有达到限制时,快速计数查找可能会节省你一些时间,因为你避免了更复杂的删除。但是一旦 table 已满,您无论如何都必须删除,因此计数只是额外的工作。
这应该有效:
private const val MAX_ITEMS = 3
private val TIMESTAMP_FIELD = "timestamp"
private val DELETE_FROM_CALL_LOG_TILL_TRIGGER =
String.format(
"CREATE TRIGGER %1$s AFTER INSERT ON %2$s
FOR EACH ROW
BEGIN
DELETE FROM %2$s WHERE _id =
(SELECT _id FROM %2$s ORDER BY %4$s DESC LIMIT 1 OFFSET %3$s);
END;"
, "delete_till_reached_max", TABLE_NAME, MAX_ITEMS, TIMESTAMP_FIELD)
一旦 table 中有 400 行,您也可以调用类似 trg_keep_rowcount_constant
的触发器并从代码中删除 GROUP BY null HAVING COUNT(*) > %3$s
。
演示:https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=ea3867e20e85927a2de047908771f4f1
这是一个简单的问题。
背景
根据时间戳字段,我应该在某些 table 中最多有 400 行,所以旧的将被自动删除。在这里,假设它是 3。
table 有多个字段,但时间戳在这里很重要。
问题
尽管我已经成功了(看起来 here),但出于某种原因,它让我最多只能添加一个项目,所以我只是相应地进行了调整。这意味着我得到了 4 件而不是 3 件。
private const val MAX_ITEMS = 3
private val TIMESTAMP_FIELD = "timestamp"
private val DELETE_FROM_CALL_LOG_TILL_TRIGGER =
String.format(
"CREATE TRIGGER %1$s INSERT ON %2$s
WHEN (select count(*) from %2$s)>%3$s
BEGIN
DELETE FROM %2$s WHERE %2$s._id IN " +
"(SELECT %2$s._id FROM %2$s ORDER BY %2$s.$TIMESTAMP_FIELD DESC LIMIT %3$d, -1);
END;"
, "delete_till_reached_max", TABLE_NAME, MAX_ITEMS - 1)
我试过的
我试过了:
- 将条件更改为仅插入(意味着没有
WHEN
部分) - 将
LIMIT %3$d, -1
更改为LIMIT -1 OFFSET %3$d
。还尝试了与“-1”不同的数字(尝试了 0,因为我认为它是额外的)。
问题
- 为什么我必须使用
MAX_ITEMS - 1
而不是MAX_ITEMS
?为什么它给我留下了 4 个项目而不是 3 个? - 如果我有
WHEN
有关系吗?好点了吗?
- 您省略了
BEFORE | AFTER
子句,因此默认为BEFORE
。这意味着您计算的是插入 之前 的行数,而不是插入之后的行数。 - 这取决于。起初,当 table 还没有达到限制时,快速计数查找可能会节省你一些时间,因为你避免了更复杂的删除。但是一旦 table 已满,您无论如何都必须删除,因此计数只是额外的工作。
这应该有效:
private const val MAX_ITEMS = 3
private val TIMESTAMP_FIELD = "timestamp"
private val DELETE_FROM_CALL_LOG_TILL_TRIGGER =
String.format(
"CREATE TRIGGER %1$s AFTER INSERT ON %2$s
FOR EACH ROW
BEGIN
DELETE FROM %2$s WHERE _id =
(SELECT _id FROM %2$s ORDER BY %4$s DESC LIMIT 1 OFFSET %3$s);
END;"
, "delete_till_reached_max", TABLE_NAME, MAX_ITEMS, TIMESTAMP_FIELD)
一旦 table 中有 400 行,您也可以调用类似 trg_keep_rowcount_constant
的触发器并从代码中删除 GROUP BY null HAVING COUNT(*) > %3$s
。
演示:https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=ea3867e20e85927a2de047908771f4f1