Oracle / PostgreSQL中的序列,插入语句中没有ID

时间:2015-07-21 17:43:28

标签: sql oracle postgresql sequence ddl

我尝试用聪明的序列生成器创建表来使用这个insert-strucure:

insert into SOMEUSERS (SOMEUSERS_NAME, SOMEUSERS_PASSWORD) 
values ('Artem', 'PracTimPatie');

而不是:

insert into SOMEUSERS (SOMEUSERS_ID, SOMEUSERS_NAME, SOMEUSERS_PASSWORD) 
values (2, 'Artem', 'PracTimPatie');

或这个结构:

insert into SOMEUSERS (SOMEUSERS_ID, SOMEUSERS_NAME, SOMEUSERS_PASSWORD) 
values (GEN_ID_SOMEUSERS.nextval, 'Artem', 'PracTimPatie');

当我执行以下sql脚本时:

create sequence gen_id_someUsers START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;

CREATE TABLE loc_db.someUsers
( someUsers_id number(10) DEFAULT gen_id_someUsers.NEXTVAL NOT NULL, --because of this row
  someUsers_name varchar2(50) NOT NULL,
  someUsers_password varchar2(50),
  CONSTRAINT someUsers_pk PRIMARY KEY (someUsers_id)
);

以下通知给我:

  

错误报告 - SQL错误:ORA-00984:此处不允许使用列   00984. 00000 - "栏目不允许在这里"

为清楚起见,在这种情况下说:

    ...
CREATE TABLE loc_db.someUsers
( someUsers_id number(10) NOT NULL, --correct this row
...
  

创建序列GEN_ID_SOMEUSERS。

     

表LOC_DB.SOMEUSERS已创建。

如何配置舒适的序列生成器?

(如果 PostgreSQL也是。如果可能,没有触发器(尽可能容易)

3 个答案:

答案 0 :(得分:2)

在postgres中只需使用如下序列:

CREATE TABLE SOMEUSERS (
  SOMEUSERS_ID serial NOT NULL,
  SOMEUSERS_NAME text,
  SOMEUSERS_PASSWORD text
);

您的插入语句很简单:

INSERT INTO SOMEUSERS (SOMEUSERS_NAME, SOMEUSERS_PASSWORD) 
values ('Artem', 'PracTimPatie');

如果你想查询序列,你可以像任何其他关系一样查询它。

答案 1 :(得分:2)

Oracle 12c引入了Identity columns

CREATE TABLE SOMEUSERS (
  SOMEUSERS_ID       NUMBER(10) GENERATED ALWAYS AS IDENTITY
                     CONSTRAINT SOMEUSERS__SOMEUSERS_ID__PK PRIMARY KEY,
  SOMEUSERS_NAME     VARCHAR2(50)
                     CONSTRAINT SOMEUSERS__SOMEUSERS_NAME__NN NOT NULL,
  SOMEUSERS_PASSWORD VARCHAR2(50)
);

如果您想在早期版本中执行此操作,则需要触发器和序列:

CREATE TABLE SOMEUSERS (
  SOMEUSERS_ID       NUMBER(10)
                     CONSTRAINT SOMEUSERS__SOMEUSERS_ID__PK PRIMARY KEY,
  SOMEUSERS_NAME     VARCHAR2(50)
                     CONSTRAINT SOMEUSERS__SOMEUSERS_NAME__NN NOT NULL,
  SOMEUSERS_PASSWORD VARCHAR2(50)
);
/

CREATE SEQUENCE gen_id_someUsers START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
/

CREATE OR REPLACE TRIGGER SOMEUSERS__ID__TRG 
BEFORE INSERT ON SOMEUSERS
FOR EACH ROW
BEGIN
  :new.SOMEUSERS_ID := gen_id_someUsers.NEXTVAL;
END;
/

然后您可以这样做(使用标识列或触发器与您的序列组合):

INSERT INTO SOMEUSERS (
  SOMEUSERS_NAME,
  SOMEUSERS_PASSWORD
) VALUES (
  'Name',
  'Password'
);

答案 2 :(得分:2)

其他答案已经解决了postgreSQL和Oracle 12c,所以我将在这里解决Oracle 11.2或更早版本。

从11.1 SQL参考手册:

  

DEFAULT

     

如果后续INSERT语句省略了列的值,则DEFAULT子句允许您指定要分配给列的值。表达式的数据类型必须与列的数据类型匹配。该列也必须足够长以保存此表达式。

     

DEFAULT表达式可以包含任何SQL函数,只要该函数不返回文字参数,列引用或嵌套函数调用。

     

对默认列值的限制

     

DEFAULT表达式不能包含对 PL / SQL函数或其他列的引用,伪列CURRVAL, NEXTVAL ,LEVEL,PRIOR和ROWNUM,或者日期常量没有完全说明。

(强调我的)

因此,由于您无法将sequence.NEXTVAL作为DEFAULT值,因此您基本上必须使用触发器:

CREATE OR REPLACE TRIGGER SOMEUSERS_BI
  BEFORE INSERT
  ON LOC_DB.SOMEUSERS
  FOR EACH ROW
BEGIN
  IF :NEW.SOMEUSERS_ID THEN
    :NEW.SOMEUSERS_ID := GEN_ID_SOMEUSERS.NEXTVAL;
  END IF;
END SOMEUSERS_BI;

根据我的经验,在Oracle 11.2或更早版本中使用诸如此类的触发器没有可靠的替代方案。

祝你好运。