【问题标题】:Make Postgres choose the next minimal available id让 Postgres 选择下一个最小可用 id
【发布时间】:2015-03-25 00:11:15
【问题描述】:

我想让 Postgres 选择下一个可用的第一个 id,以便在以下情况下不会发生错误:

CREATE TABLE test(
id serial PRIMARY KEY,
name varchar
);

然后:

INSERT INTO test VALUES (2,'dd');
INSERT INTO test (name) VALUES ('aa');
INSERT INTO test (name) VALUES ('bb');

这将产生一个约束错误,因为id 是主要的。
如何告诉 Postgres 插入具有下一个空闲 id 的记录?

【问题讨论】:

  • 你不需要告诉它选择。它会自动完成。只需抑制 id 信息。当然,如果主是串行的。 Postgresql 将为它创建一个序列
  • @Jorge:我认为 OP 在他们的数据库中已经有乱序的 ID,并且想知道如何解决问题......
  • 您不应该为序列列提供手动值。为什么你认为你需要这样做?
  • 我明白,但在我的场景中:用户可以指定他想要的 id 或者他不指定 id
  • 承担用户控制ID的责任。

标签: database postgresql database-design auto-increment gaps-and-islands


【解决方案1】:

通常最好从不否决serial 列中的默认值。如果您有时需要手动提供 id 值,请将serial 列的标准DEFAULT 子句nextval('sequence_name') 替换为省略现有值的自定义函数。

基于这个虚拟表:

CREATE TABLE test (test_id serial PRIMARY KEY, test text);

功能:

CREATE OR REPLACE FUNCTION f_test_test_id_seq(OUT nextfree bigint) AS
$func$
BEGIN
LOOP
   SELECT INTO nextfree  val
   FROM   nextval('test_test_id_seq'::regclass) val  -- use actual name of sequence
   WHERE  NOT EXISTS (SELECT 1 FROM test WHERE test_id = val);

   EXIT WHEN FOUND;
END LOOP; 
END
$func$  LANGUAGE plpgsql;

更改默认值:

ALTER TABLE test ALTER COLUMN test_id SET DEFAULT f_test_test_id_seq();

它不再是严格意义上的serial,但serial 无论如何只是一个便利功能:

如果您在 serial 列之上构建它,SEQUENCE 将自动由表列“拥有”,这可能是一件好事。

这是一个稍快的变体:

表和序列名称是硬编码的。您可以轻松地参数化序列名称(如链接的答案)甚至表名称 - 并使用 EXECUTE 使用动态语句测试存在。会给你一个通用函数,但调用会贵一些。

CREATE OR REPLACE FUNCTION f_nextfree(_tbl regclass
                                     , _col text
                                     , _seq regclass
                                     , OUT nextfree bigint) AS
$func$
BEGIN
LOOP
   EXECUTE '
   SELECT val FROM nextval($1) val WHERE NOT EXISTS (
      SELECT 1 FROM ' || _tbl || ' WHERE ' || quote_ident(_col) || ' = val)'
   INTO  nextfree
   USING _seq;

   EXIT WHEN nextfree IS NOT NULL;
END LOOP; 
END
$func$  LANGUAGE plpgsql;

ALTER TABLE test2 ALTER COLUMN test2_id
SET DEFAULT f_nextfree('test2', 'test2_id', 'test2_test2_id_seq');

SQL Fiddle.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2011-04-13
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    相关资源
    最近更新 更多