数据库ID sqlite持续增加

qpgpyjmq  于 2023-02-05  发布在  SQLite
关注(0)|答案(1)|浏览(122)

这是我创建数据库的方法。

CREATE TABLE $_tableName(
        id INTEGER NOT NULL PRIMARY KEY,
        category TEXT,
        content TEXT,
        date TEXT
        )

当我删除任何数据时,id从它停止的地方继续。例如,我有范围为1-10的id数据。当从数据库中删除内容编号3时,新添加的值id变为11。我想将新值保存在空白的3字段中。

Future<int> add(NoteDbModel saveDbModel) async {
    Database db = await instance.database;
    return await db.insert(_tableName, saveDbModel.toMap());
  }

  Future<int> remove(int id) async {
    Database db = await instance.database;
    return await db.delete(_tableName, where: 'id = ?', whereArgs: [id]);
  }
ljo96ir5

ljo96ir51#

    • id的目的是唯一地id**标识一行。

除了虚拟表和WITHOUT ROWID表之外,SQLite以特殊方式处理包含定义为INTEGERPRIMARY KEY的列的表。该列是可归类为SUPER KEY的列的别名,即隐藏的rowid列的别名。
SQLite支持(优化)使用rowid或其别名。当扫描/搜索底层索引时,扫描/搜索的速度可以达到两倍。
正如您所发现的,如果在插入一个带有这样一个列的行时,为该列提供了一个值,则会生成该值,这就像max((SELECT id FROM theTable))+1一样简单。
因此,如果删除了最后一行以外的任何行,则该值保持未使用状态(请参见以下注解,因为这实际上并不是全部事实)。

  • 除非使用了最高可能值,否则SQlite将尝试查找未使用的但更低的值
  • 除非在引发SQLITE_FULL错误时使用AUTOINCREMENT编码。
  • SQLite的AUTOINCREMENT效率很低,并且不能确定单调增加的生成值的生成。

尝试将列用于任何其他目的,例如希望它是特定的值以适合人类,通常会导致问题,例如您所提出的问题。

    • 演示**(包括使用insert插入第一个未使用的ID,即使不推荐
  • 请注意,这里只介绍了简单的SQL,可以对其进行调整

:-

/* Just in case demo environment was not cleaned up */
DROP TABLE IF EXISTS demo;

/* The demo table */
CREATE TABLE IF NOT EXISTS demo (id INTEGER NOT NULL PRIMARY KEY, another_column TEXT DEFAULT 'whatever');

/* Add some data (ids 1 -10 in all likeliehood) */
WITH 
    cte(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cte LIMIT 10)
    INSERT INTO demo (another_column) SELECT 'somedata' FROM cte
;
SELECT rowid,* FROM demo; /* RESULT 1 - Original data */

/* Drop odd numbered ids */
DELETE FROM demo WHERE id % 2;
SELECT rowid,* FROM demo; /* RESULT 2 - After deleting odd # ids */

/* replicate issue i.e. add 7 new rows (ids 11-17) */
WITH 
    cte(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cte LIMIT 7)
INSERT INTO demo (another_column) SELECT 'newdata #'||x FROM cte;
SELECT rowid,* FROM demo; /* RESULT 3 - ids not filling free/unused ids */

/* Revert to original with dropped odd ids */
DELETE FROM demo WHERE id > 10;
SELECT rowid,* FROM demo;

/* Insert new row using the first unused id, if one */
WITH
    cte_extraValueToInsert(newValue) AS (SELECT 'the new data to be inserted 1'),
    cte(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cte LIMIT (SELECT max(id) FROM demo)),
    cte_missing(expected) AS (SELECT x FROM cte WHERE (SELECT id FROM demo WHERE demo.id=x) IS NULL ORDER BY x ASC LIMIT 1)
    INSERT INTO demo (id,another_column) VALUES(
        (CASE 
            WHEN (SELECT expected FROM cte_missing) 
            THEN (SELECT expected FROM cte_missing) 
            ELSE (SELECT max(id)+1 FROM demo) 
        END),
        (SELECT * FROM cte_extraValueToInsert)
        )
;

/* Insert second new row using the first unused id, if one */
WITH
    cte_extraValueToInsert(newValue) AS (SELECT 'the new data to be inserted 2'),
    cte(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cte LIMIT (SELECT max(id) FROM demo)),
    cte_missing(expected) AS (SELECT x FROM cte WHERE (SELECT id FROM demo WHERE demo.id=x) IS NULL ORDER BY x ASC LIMIT 1)
    INSERT INTO demo (id,another_column) VALUES(
        (CASE 
            WHEN (SELECT expected FROM cte_missing) 
            THEN (SELECT expected FROM cte_missing) 
            ELSE (SELECT max(id)+1 FROM demo) 
        END),
        (SELECT * FROM cte_extraValueToInsert)
        )
;
SELECT rowid,* FROM demo;

/* Clean up DEMO environment */
DROP TABLE IF EXISTS demo;
  • cte是C常见TableE表达式,它们实际上是一个临时表,其生命周期取决于SQL/Query的执行
  • 它们甚至可以用于递归(代码中的一些cte是递归的)。
    • 演示结果**

1.使用生成的ID初始填充行之后:-

1.删除奇数id后

1.添加7行生成的ID(即问题)后,即错误

1.删除错误插入后(返回2))

1.使用fix(原文如此)SQL插入两行后

  • 请注意,这只是一个原则上的演示,它还没有经过彻底的测试(例如,使用它时,没有未使用)。不建议使用它。

相关问题