【问题标题】:SQLite auto-increment non-primary key fieldSQLite 自增非主键字段
【发布时间】:2011-10-22 08:51:30
【问题描述】:

是否可以在每次插入时自动增加一个非主键?

例如,我想要一个日志,其中每个日志条目都有一个主键(供内部使用)和一个修订号(我希望自动递增的 INT 值)。

作为一种解决方法,这可以通过序列来完成,但我相信 SQLite 不支持序列。

【问题讨论】:

  • 您可以使用AFTER INSERT 触发器来模拟 SQLite 中的序列。详情请见my answer below

标签: sql sqlite auto-increment


【解决方案1】:

您可以在插入时选择 max(id)+1。

例如:

INSERT INTO Log (id, rev_no, description) VALUES ((SELECT MAX(id) + 1 FROM log), 'rev_Id', 'some description')

请注意,这将在空表上失败,因为不会有 id 为 0 的记录,但您可以添加第一个虚拟条目或将 sql 语句更改为:

INSERT INTO Log (id, rev_no, description) VALUES ((SELECT IFNULL(MAX(id), 0) + 1 FROM Log), 'rev_Id', 'some description')

【讨论】:

  • 我使用了虚拟条目。将真实数据添加到表中后,我将其删除。
  • 第二条语句对我不起作用。没有 ISNULL 这样的关键字。这个做到了:INSERT INTO Log (id, rev_no, description) VALUES ((SELECT IFNULL(MAX(id), 0)) + 1 FROM Log), 'rev_Id', 'some description')
  • @DamianHickey 感谢您的更正。 ISNULL 来自 MS SQL Server,它显然不适用于 SQLite。
  • 对于未来的读者:上面的 sn-p 在 IFNULL 上有 1 个额外的右括号。应该是这样的:` INSERT INTO Log (id, rev_no, description) VALUES ((SELECT IFNULL(MAX(id), 0) + 1 FROM Log), 'rev_Id', 'some description') `
  • @pedja 已编辑 - 您可以删除您的评论和(我会尽量记住删除我的:)
【解决方案2】:

SQLite 自动创建一个唯一的行 ID (rowid)。当您使用“select * ...”时,通常会忽略此字段,但您可以使用“select rowid,* ...”获取此 id。请注意,根据 SQLite 文档,他们不鼓励使用自动增量。

create table myTable ( code text, description text );
insert into myTable values ( 'X', 'some descr.' );
select rowid, * from myTable;

:: 结果将是; 1|X|一些描述。

如果您使用此 id 作为外键,您可以导出 rowid - 并导入正确的值以保持数据完整性;

insert into myTable values( rowid, code text, description text ) values
( 1894, 'X', 'some descr.' );

【讨论】:

  • 我认为这应该是正确的答案,我从来不知道有隐藏的rowid 字段,谢谢。我想真的不需要创建额外的 id 字段来跟踪自动递增的 id。
【解决方案3】:

您可以使用触发器 (http://www.sqlite.org/lang_createtrigger.html) 来检查先前的最高值,然后将其递增,或者如果您在存储过程中执行插入操作,则将相同的逻辑放入其中。

【讨论】:

  • 所以...如果我理解正确,CREATE TRIGGER update_revision INSERT OF single_string ON data BEGIN UPDATE data SET revision = (SELECT max(revision) from data ) + 1 WHERE single_string = ? END; 是正确的语法吗?
  • 不确定语法,因为我没有使用过 SQLite,但你有正确的想法。试一试,看看会发生什么:)
【解决方案4】:

我的回答和伊卡洛斯的很相似,所以我不用提了。

如果需要,您可以以更高级的方式使用 Icarus 的解决方案。以下是火车预订系统的座位可用性表示例。

insert into Availiability (date,trainid,stationid,coach,seatno)
    values (
        '11-NOV-2013',
        12076,
        'SRR',
        1,
        (select max(seatno)+1
            from Availiability
            where date='11-NOV-2013'
                and trainid=12076
                and stationid='SRR'
                and coach=1)
    );

【讨论】:

    【解决方案5】:

    您可以使用AFTER INSERT trigger 在 SQLite 中模拟序列(但请注意,如果删除行,数字可能会被重用)。这将使您的INSERT INTO 声明更容易。

    在以下示例中,revision 列将自动递增(当然,除非INSERT INTO 语句明确为其提供了值):

    CREATE TABLE test (
        id INTEGER PRIMARY KEY NOT NULL,
        revision INTEGER,
        description TEXT NOT NULL
    );
    
    CREATE TRIGGER auto_increment_trigger
        AFTER INSERT ON test
        WHEN new.revision IS NULL
        BEGIN
            UPDATE test
            SET revision = (SELECT IFNULL(MAX(revision), 0) + 1 FROM test)
            WHERE id = new.id;
        END;
    

    现在您可以像这样简单地插入一个新行,revision 列将自动递增:

    INSERT INTO test (description) VALUES ('some description');
    

    【讨论】:

      猜你喜欢
      • 2020-07-18
      • 2016-06-04
      • 1970-01-01
      • 2011-03-14
      • 1970-01-01
      • 2015-05-11
      • 2012-01-21
      • 2013-04-18
      • 2021-05-29
      相关资源
      最近更新 更多