在PostgreSQL中插入数据

5
有没有一种方法可以向一个没有自动递增ID的表中插入新记录而不需要特别输入ID。我只想让ID成为lastId+1。 INSERT INTO lists VALUES (lastId+1,'KO','SPH', '5') //新的ID

5
所以你希望行为像一个序列(“自动增量”),但不使用序列。为什么不呢?这些存在的目的是为了解决并发插入时可能遇到的问题。 - deceze
我只想插入一条新记录,而不改变数据库结构... - Jacob
如果这是一个特殊情况,那就好了……如果这是正常的操作方式,也许你应该改变你的数据库结构。 - deceze
数据库设计不是由我来完成的 :) - Jacob
2
那么你可能需要与负责人交谈。 :) - deceze
这太疯狂了,一个序列勉强符合“数据库结构”的定义。 - Strae
1个回答

17

不要这样做!绝对不要甚至不要考虑这么做!

这个错误的解决方案可能看起来(实际上并不是)能对你起作用:

INSERT INTO lists VALUES ((SELECT max(id)+1 FROM lists),'KO','SPH', '5');

但是,如果有人在你同时插入数据,你们都会得到相同的id,这将导致无效结果。您真的应该使用一个sequence或一些更可靠的机制(当您无法在序列中留下空洞时,辅助表是常见的选择,但它也有一些缺点[它会锁定])。您甚至可以使用serial数据类型使其更加简便(它会在底层创建一个序列):

CREATE TABLE lists(id serial, col2 text, col3 text, ...);
-- If you don't specify "id", it will autogenerate for you:
INSERT INTO lists(col2, col3, ...) VALUES('KO','SPH', ...);
-- You can also specify using DEFAULT (the same as above):
INSERT INTO lists(id, col2, col3, ...) VALUES(DEFAULT, 'KO','SPH', ...);

如果您真的、真的、真的无法创建和使用序列,您可以像上面那样操作,但是您需要处理异常(假设 id 字段是PK或UK,并使用读取提交的事务),就像这样(在PL/pgSQL中):

DECLARE
    inserted bool = false;
BEGIN
    WHILE NOT inserted LOOP;
        BEGIN
            INSERT INTO lists
            VALUES ((SELECT coalesce(max(id),0)+1 FROM lists),'KO','SPH', '5');
            inserted = true;
        EXCEPTION
            WHEN unique_violation THEN
                NULL; -- do nothing, just try again
        END;
    END LOOP;
END;

但是,我强烈建议您避免使用它:使用序列,并且很高兴... =D

此外,我知道这只是一个例子,但在INSERT INTO子句中使用显式列列表。


如果没有数据,你执行max(id) + 1会发生什么? - maazza
@maazza:然后 max 将返回 NULL(而 NULL+1 返回 NULL),您可以使用 COALESCE 轻松处理它,我将更新答案来实现这一点。 - MatheusOl
4
公平地说,警告有点夸张。只要在id属性上设置了关键限制,最坏的情况是一个插入操作将失败。 - beldaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接