运行On Conflict命令

时间:2016-08-19 06:44:46

标签: sql postgresql postgresql-9.5

有一个表,我需要填充数据,同时摆脱重复。我正在使用ON CONFLICT ... DO NOTHING。问题是,当表有一个auto_increment primary_key字段-lets称之为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个记录,则最大/最后一个id字段的值应为4?

在我目前的情况下,我正在处理一个大数据集,其中插入了120万条记录,但最后一条记录的id值为6200万。如果可能的话,这就是我想要避免的。

2 个答案:

答案 0 :(得分:1)

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

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;

答案 1 :(得分:0)

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

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

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

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