当 运行 On Conflict 命令时控制 table 的主键值

Controlling a table's primary key value when running On Conflict command

得到一个 table,我需要在删除重复项的同时填充数据。我正在使用 ON CONFLICT ... DO NOTHING。问题是,当 table 有一个 auto_increment primary_key 字段 - 让我们称之为 id- 时,即使没有插入重复项,该字段似乎也会继续增加id 字段值远远高于已成功插入的记录数。

不幸的是SQL Fiddle目前不支持postgresql 9.5所以我将复制粘贴下面的代码。

CREATE TABLE table_one
(
    id    serial primary key,
    col_foo        VARCHAR(40) not null unique,
    col_bar        VARCHAR(20)
);

INSERT into table_one (col_foo, col_bar) 
VALUES ('1a', '1b'), ('2a', '2b'), ('1a', '2b'),('1a', Null), ('3a', '1b'), ('4a', '2b'), ('1a', '2b'),('1a', Null) 
ON CONFLICT (col_foo) DO NOTHING;

如果你运行在postgresql 9.5上,你会发现最终的主键是6,而只有4条记录。是否可以确保如果成功插入 6 条记录中的 4 条记录,那么 max/last id 字段的值应为 4?

在我当前的案例中,我正在处理一个大型数据集,其中插入了 120 万条记录,但最后一条记录的 id 值为 6200 万。这就是我尽可能避免的事情。

您无法真正改变 ON CONFLICT 的行为。它所允许的只是更新冲突行而不是创建新行。

您可以重置序列并在之后重新分配 ID:

SELECT setval('table_one_id_seq', 1);
UPDATE table_one SET id = nextval('table_one_id_seq');

当然,您永远不应依赖最后一个 ID 来获取行数。如果您担心 ID 不足 运行,请使用 bigserial 而不是 serial。

您当然可以使用临时文件 table 来捕获和抑制重复项:

CREATE TABLE table_one
(
    id    serial primary key,
    col_foo        VARCHAR(40) not null unique,
    col_bar        VARCHAR(20)
);

CREATE TEMP TABLE temp_one
(
    id    serial primary key, -- dont actually need this
    col_foo        VARCHAR(40) not null unique,
    col_bar        VARCHAR(20)
);

INSERT into temp_one (col_foo, col_bar)
VALUES ('1a', '1b'), ('2a', '2b'), ('1a', '2b'),('1a', Null), ('3a', '1b'), ('4a', '2b'), ('1a', '2b'),('1a', Null)
ON CONFLICT (col_foo) DO NOTHING
        ;

INSERT into table_one (col_foo, col_bar)
SELECT col_foo, col_bar FROM temp_one
ON CONFLICT (col_foo) DO NOTHING -- wont need this
         -- (except for suppressing already-existing duplicates)
        ;

SELECT * FROM temp_one;
SELECT * FROM table_one;