【问题标题】:Sequence in Oracle/PostgreSQL with no ID in insert statementOracle/PostgreSQL 中的序列,插入语句中没有 ID
【发布时间】:2015-10-11 07:41:44
【问题描述】:

我正在尝试使用巧妙的序列生成器创建表以使用此插入结构:

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 中,只需将列定义为 serial: postgresql.org/docs/current/static/… 在 Oracle 11g 之前,您不能使用序列作为默认值。您必须在该版本中使用触发器。在 Oracle 12g 中,您实际上可以使用与您正在尝试执行的操作非常相似的语法。

标签: sql oracle postgresql sequence ddl


【解决方案1】:

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

来自 11.1 SQL 参考手册:

默认

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

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

默认列值的限制

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

(强调我的)

因此,由于您不能将sequence.NEXTVAL 作为默认值,您基本上将不得不使用触发器:

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 或更早版本中使用触发器之外,没有其他可靠的替代方法。

祝你好运。

【讨论】:

    【解决方案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'
    );
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2019-01-15
        • 1970-01-01
        • 2021-05-26
        • 2011-10-30
        • 1970-01-01
        • 1970-01-01
        • 2019-04-21
        相关资源
        最近更新 更多