sql—如何在sqlite中使用触发器为特定表设置最大项?

m3eecexj  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(377)

这是一个简单的问题。

背景

根据timestamp字段,我应该在某个表中最多有400行,所以旧的将被自动删除。在这里,假设是3。
表有各种字段,但时间戳在这里很重要。

问题

尽管我已经成功了(看这里),但出于某种原因,它让我最多增加了一个项目,所以我只是相应地调整了它。这意味着我得到的不是3件,而是4件。

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)

我试过的

我试过:
将条件更改为just being insertion(意思是没有 WHEN 零件)
改变 LIMIT %3\$d, -1LIMIT -1 OFFSET %3\$d . 还尝试了一个不同于“-1”的数字(尝试了0,因为我认为它是多余的)。

问题

为什么我要用 MAX_ITEMS - 1 而不仅仅是 MAX_ITEMS ? 为什么我只剩下4件而不是3件?
有没有关系 WHEN 在那里?好点了吗?

tkclm6bt

tkclm6bt1#

你遗漏了 BEFORE | AFTER 条款,所以 BEFORE 默认情况下。这意味着您在计算插入之前的行,而不是插入之后的行。
这要看情况。首先,当表尚未达到限制时,快速计数查找可以节省一些时间,因为可以避免更复杂的删除。但是一旦表满了,就必须删除,所以计数只是额外的工作。
这应该起作用:

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)

一旦表中有400行,就可以调用触发器 trg_keep_rowcount_constant 并移除 GROUP BY null HAVING COUNT(*) > %3\$s 从密码里。
演示:https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=ea3867e20e85927a2de047908771f4f1

相关问题