是否可以(模拟?)在Sqlite中对复合PK进行自动增量?

是否可以(模拟?)在Sqlite中对复合PK进行自动增量?,sqlite,auto-increment,compound-key,Sqlite,Auto Increment,Compound Key,根据SQLite,获取自动递增列的唯一方法是在主键上 我需要一个复合主键,但我也需要自动递增。有没有一种方法可以在SQLite中实现这两个目标 我在PostgreSQL中编写的表格的相关部分: CREATE TABLE tstage ( id SERIAL NOT NULL, node INT REFERENCES nodes(id) NOT NULL, PRIMARY KEY (id,node),

根据SQLite,获取自动递增列的唯一方法是在主键上

我需要一个复合主键,但我也需要自动递增。有没有一种方法可以在SQLite中实现这两个目标

我在PostgreSQL中编写的表格的相关部分:

CREATE TABLE tstage (
    id                   SERIAL NOT NULL,
    node                 INT REFERENCES nodes(id) NOT NULL,
    PRIMARY KEY (id,node),
    -- ... other columns
);

此要求的原因是,所有节点最终都会将其数据转储到一个集中式节点,在该节点中,如果使用单列PK,则会发生冲突。

文档是正确的。 但是,可以在触发器中重新实现自动增量逻辑:

CREATE TABLE tstage (
    id    INT,  -- allow NULL to be handled by the trigger
    node  INT REFERENCES nodes(id) NOT NULL,
    PRIMARY KEY (id, node)
);

CREATE TABLE tstage_sequence (
    seq INTEGER NOT NULL
);
INSERT INTO tstage_sequence VALUES(0);

CREATE TRIGGER tstage_id_autoinc
AFTER INSERT ON tstage
FOR EACH ROW
WHEN NEW.id IS NULL
BEGIN
    UPDATE tstage_sequence
    SET seq = seq + 1;

    UPDATE tstage
    SET id = (SELECT seq
              FROM tstage_sequence)
    WHERE rowid = NEW.rowid;
END;

(如果有多个表,请使用带有表名的通用
my_序列
表。)

文档正确。 但是,可以在触发器中重新实现自动增量逻辑:

CREATE TABLE tstage (
    id    INT,  -- allow NULL to be handled by the trigger
    node  INT REFERENCES nodes(id) NOT NULL,
    PRIMARY KEY (id, node)
);

CREATE TABLE tstage_sequence (
    seq INTEGER NOT NULL
);
INSERT INTO tstage_sequence VALUES(0);

CREATE TRIGGER tstage_id_autoinc
AFTER INSERT ON tstage
FOR EACH ROW
WHEN NEW.id IS NULL
BEGIN
    UPDATE tstage_sequence
    SET seq = seq + 1;

    UPDATE tstage
    SET id = (SELECT seq
              FROM tstage_sequence)
    WHERE rowid = NEW.rowid;
END;

(如果有多个表,则使用带有表名的公共
my_序列
表。)

触发器可以工作,但很复杂。更简单地说,您可以避免使用串行ID。一种方法是,你可以使用。不幸的是,我找不到让SQLite默认为您生成GUID的方法,因此您必须在应用程序中生成GUID。也没有GUID类型,但可以将其存储为字符串或字符串

或者,您的其他列中可能有一些内容可以作为合适的键。如果您知道插入不会比选择的时间戳格式()的解析更频繁,那么
(节点,时间戳列)
可能是一个好的主键


或者,您可以使用SQLite的
AUTOINCREMENT
,但可以通过
SQLite\u sequence
表,这样生成的序列就不会发生冲突。由于
rowid
是一个64位的数字,您可以通过为每个节点生成一个唯一的32位数字(IP地址是一个方便的,可能是唯一的32位数字)并将其左移32位,或者等效地将其乘以4294967296来实现。因此,64位的
rowid
实际上成为两个串联的32位数字,
节点ID,记录ID
,保证不会发生冲突,除非一个节点生成超过40亿条记录。

触发器工作,但很复杂。更简单地说,您可以避免使用串行ID。一种方法是,你可以使用。不幸的是,我找不到让SQLite默认为您生成GUID的方法,因此您必须在应用程序中生成GUID。也没有GUID类型,但可以将其存储为字符串或字符串

或者,您的其他列中可能有一些内容可以作为合适的键。如果您知道插入不会比选择的时间戳格式()的解析更频繁,那么
(节点,时间戳列)
可能是一个好的主键

或者,您可以使用SQLite的
AUTOINCREMENT
,但可以通过
SQLite\u sequence
表,这样生成的序列就不会发生冲突。由于
rowid
是一个64位的数字,您可以通过为每个节点生成一个唯一的32位数字(IP地址是一个方便的,可能是唯一的32位数字)并将其左移32位,或者等效地将其乘以4294967296来实现。因此,64位的
rowid
实际上变成了两个串联的32位数字,
NODE\u ID,RECORD\u ID
,保证不会冲突,除非一个节点生成超过40亿条记录。

怎么样

假设

  • 只需要PK中的唯一性,不需要序列性
  • 源表有一个PK
创建带有一个额外列的中心表,节点编号

CREATE TABLE tstage (
    node  INTEGER NOT NULL,
    id    INTEGER NOT NULL,   <<< or whatever the source table PK is
    PRIMARY KEY (node, id)
       :
);
不需要在中心表上维护另一个自动递增列,因为nodenumber+sourcetable\u id将始终是唯一的。

如何

假设

  • 只需要PK中的唯一性,不需要序列性
  • 源表有一个PK
创建带有一个额外列的中心表,节点编号

CREATE TABLE tstage (
    node  INTEGER NOT NULL,
    id    INTEGER NOT NULL,   <<< or whatever the source table PK is
    PRIMARY KEY (node, id)
       :
);

不需要在中心表上维护另一个自动递增列,因为nodenumber+sourcetable_id将始终是唯一的。

如果有索引,则从t选择max(id)非常有效。触发器是否意味着事务,或者我需要在
UPDATE tstage\u sequence…
之前显式开始一个事务以防止客户端之间的竞争吗?触发器总是与触发命令在同一个事务中运行。我想我的问题更多的是触发器本身是否是原子的。如果存在争用,
UPDATE tstage\u序列
可能触发两次,那么
UPDATE tstage
将失败,并在第二个客户端上出现唯一密钥冲突。我希望找到一种使触发器原子化的方法,因此我不必在客户端代码中检查此故障。SQLite事务总是完全序列化的(因为没有并发)。
SELECT max(id)FROM t t
在有索引的情况下非常有效。触发器是否意味着事务,或者我需要在
UPDATE tstage\u sequence…
之前显式开始一个事务以防止客户端之间的竞争吗?触发器总是与触发命令在同一个事务中运行。我想我的问题更多的是触发器本身是否是原子的。如果存在争用,
UPDATE tstage\u序列
可能触发两次,那么
UPDATE tstage
将失败,并在第二个客户端上出现唯一密钥冲突。我希望找到一种使触发器原子化的方法,因此我不必在客户端代码中检查此故障。SQLite事务总是完全序列化的(因为没有并发)。
(节点,id)
本质上已经是一个GUID。我明白你的意思了——使用某种位图将它们组合成一个db字段。
(节点,id)
本质上已经是一个GUID了。我明白你的意思了——使用某种位图将它们组合成一个db字段。