簡體   English   中英

Oracle / PostgreSQL中的序列,在插入語句中沒有ID

[英]Sequence in Oracle/PostgreSQL with no ID in insert statement

我嘗試使用巧妙的序列生成器創建表以使用此插入結構:

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也是如此 。如果沒有觸發器,則盡可能輕松)

在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');

如果您想查詢序列,則可以像查詢其他任何關系一樣查詢它。

Oracle 12c引入了標識列

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;
/

然后,您可以執行此操作(將Identity列或觸發器與您的序列結合使用):

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

其他答案已經解決了postgreSQL和Oracle 12c,因此在這里我將介紹Oracle 11.2或更早版本。

從《 11.1 SQL參考手冊》中:

默認

如果后續的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或更早版本)更可靠的選擇。

祝你好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM