如何在 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)

我试过的

我试过了:

问题

  1. 为什么我必须使用 MAX_ITEMS - 1 而不是 MAX_ITEMS ?为什么它给我留下了 4 个项目而不是 3 个?
  2. 如果我有 WHEN 有关系吗?好点了吗?
  1. 您省略了 BEFORE | AFTER 子句,因此默认为 BEFORE。这意味着您计算的是插入 之前 的行数,而不是插入之后的行数。
  2. 这取决于。起初,当 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