始终在串行列中使用下一个序列(不允许用户值)

时间:2016-06-26 07:13:31

标签: database oracle postgresql

在PostgreSQL中,我想创建一个带有自动增量列的表,用户无法指定自定义值。

在Oracle中,您有两种方法可以创建自动增量列。

在第一个示例中,如果用户没有显示值,则id列会自动递增。这是postgres中SERIAL的当前实现。

CREATE TABLE identity_test_tab ( 
   id NUMBER GENERATED BY DEFAULT AS DENTITY,
   description VARCHAR2(30) 
);

在下一个示例中,id列始终自动递增,用户无法指定任何其他值。

CREATE TABLE identity_test_tab (
  id          NUMBER ALWAYS AS IDENTITY,
  description VARCHAR2(30)
);

我想知道postgres中第二个例子的等价物吗?

2 个答案:

答案 0 :(得分:3)

如果要确保始终从序列中获取值,则需要触发器。在Postgres中没有等同于generated always

create table foo (id integer not null primary key);
create sequence foo_id_seq;
alter sequence foo_id_seq owned by foo.id; -- this is essentially what `serial` does in the background

create function generate_foo_id()
  returns trigger
as
$$
begin
  new.id := nextval('foo_id_seq');
  return new;
end;
$$
language plpgsql;    

create trigger foo_id_trigger
  before insert on foo
  for each row execute procedure generate_foo_id();

上面将使用序列值以foo.id静默替换任何用户提供的值。如果您在执行此操作时需要显式错误,请在触发器函数中引发异常:

create function generate_foo_id()
  returns trigger
as
$$
begin
  if new.id is not null then 
     raise 'No manual value for id allowed';
  end if;
  new.id := nextval('foo_id_seq');
  return new;
end;
$$
language plpgsql;

引发异常会中止当前事务,并强制应用程序插入值以进行回滚并正确执行。

答案 1 :(得分:2)

只能通过特定列的授权插入来完成:

drop table if exists t;
create table t(i serial, x text, y int);
grant insert (x,y) on table t to abelisto;
grant usage on sequence t_i_seq to abelisto;
grant select on table t to abelisto;

然后:

postgres=# insert into t(i,x,y) values(10,'x',1);
ERROR:  permission denied for relation t
postgres=# insert into t(i,x,y) values(default,'x',1);
ERROR:  permission denied for relation t
postgres=# insert into t(x,y) values('x',1);
INSERT 0 1
postgres=# select * from t;
 i | x | y 
---+---+---
 1 | x | 1
(1 row)