如何创建正常的序列?

时间:2017-10-09 08:10:32

标签: oracle plsql sequence

我创建了一个表,一个序列和一个触发器。我用正确的数据添加第一条记录。在ID列中我有1.然后我尝试添加包含无效数据的记录,我收到错误。更正错误,将数据添加到表。不幸的是,新记录的ID = 3.为什么会发生这种情况?无论尝试输入无效数据的次数如何,我都会在ID列中有连续的数字。

  --CREATING TABLE TEST
CREATE TABLE TEST_TABLE 
   ("ID" NUMBER PRIMARY KEY NOT NULL, 
    "NAME" VARCHAR2(20) NOT NULL,  
    "PERSONAL_ID_NUM" VARCHAR(11) UNIQUE NOT NULL,
     CONSTRAINT "LENGTH_PIN" CHECK (LENGTH(PERSONAL_ID_NUMBER) = 11),
     CONSTRAINT "IS_DIGIT_PIN" CHECK (REGEXP_LIKE(P_PESEL2,'^[0-9]*$'))
     );

--CREATING SEQUENCE
CREATE SEQUENCE SEQ_TEST_TABLE START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE NOCYCLE CACHE 2;

--CREATING TRIGGER
CREATE OR REPLACE TRIGGER TR_TEST_TABLE
BEFORE INSERT ON TEST_TABLE FOR EACH ROW 
BEGIN
SELECT SEQ_TEST_TABLE.NEXTVAL
INTO :new.ID
FROM dual;
END;

--INSERT DATA, VALID VALUES
INSERT INTO TEST_TABLE(ID, NAME, PERSONAL_ID_NUM)
VALUES(SEQ_TEST_TABLE.NEXTVAL, 'JOHN', '12345678901');

--CHECK TABLE
SELECT * FROM TEST_TABLE;

--TRYING INSERT NOT VALID VALUES
INSERT INTO TEST_TABLE(ID, NAME, PERSONAL_ID_NUM)
VALUES(SEQ_TEST_TABLE.NEXTVAL, 'EMIL', '1234567890A');

--INSERT VALID VALUES
INSERT INTO TEST_TABLE(ID, NAME, PERSONAL_ID_NUM)
VALUES(SEQ_TEST_TABLE.NEXTVAL, 'EMIL', '12345678902');

--CHECK TABLE (NEW ROW HAVE ID = 3)
SELECT * FROM TEST_TABLE;

2 个答案:

答案 0 :(得分:1)

  

不幸的是,新记录的ID = 3.为什么会发生这种情况?

您正在进行第一次插入:

INSERT INTO TEST_TABLE(ID, NAME, PERSONAL_ID_NUM)
VALUES(SEQ_TEST_TABLE.NEXTVAL, 'JOHN', '12345678901');

从序列中获取下一个值1,然后触发器运行并将ID值替换为序列中的下一个值2

重复下一个插入,它将获得3,然后触发器将替换为4。因此,您为每个插入使用两个序列值。

你想要做的是不使用原始插入中的序列,只是让触发器提供该值(或者不要使用触发器,只需在DML语句中使用SEQ_TEST_TABLE.NEXTVAL - 但不是两个):

SQL Fiddle

Oracle 11g R2架构设置

CREATE TABLE TEST_TABLE 
   ("ID" NUMBER PRIMARY KEY NOT NULL, 
    "NAME" VARCHAR2(20) NOT NULL,  
    "PERSONAL_ID_NUM" VARCHAR(11) UNIQUE NOT NULL,
     CONSTRAINT "LENGTH_PIN" CHECK (LENGTH(PERSONAL_ID_NUM) = 11)
     )
/

CREATE SEQUENCE SEQ_TEST_TABLE START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE NOCYCLE CACHE 2
/

--CREATING TRIGGER
CREATE OR REPLACE TRIGGER TR_TEST_TABLE
BEFORE INSERT ON TEST_TABLE FOR EACH ROW 
BEGIN
  :new.ID := SEQ_TEST_TABLE.NEXTVAL;
END;
/

INSERT INTO TEST_TABLE(NAME, PERSONAL_ID_NUM)
VALUES('JOHN', '12345678901')
/

INSERT INTO TEST_TABLE(NAME, PERSONAL_ID_NUM)
VALUES('EMIL', '1234567890A')
/

INSERT INTO TEST_TABLE(NAME, PERSONAL_ID_NUM)
VALUES('EMIL', '12345678902')
/

查询1

SELECT * FROM TEST_TABLE

<强> Results

| ID | NAME | PERSONAL_ID_NUM |
|----|------|-----------------|
|  1 | JOHN |     12345678901 |
|  2 | EMIL |     1234567890A |
|  3 | EMIL |     12345678902 |

答案 1 :(得分:0)

从Oracle 12c版本1开始,Identity Column可用于自动生成序列。查看此文档

https://oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1

基本上,格式是(对于上表):

CREATE TABLE TEST_TABLE 
  ("ID" NUMBER GENERATED ALWAYS AS IDENTITY, 
"NAME" VARCHAR2(20) NOT NULL,  
"PERSONAL_ID_NUM" VARCHAR(11) UNIQUE NOT NULL,
 CONSTRAINT "TEST_PK" PRIMARY_KEY("ID"),
 CONSTRAINT "LENGTH_PIN" CHECK (LENGTH(PERSONAL_ID_NUMBER) = 11),
 CONSTRAINT "IS_DIGIT_PIN" CHECK (REGEXP_LIKE(P_PESEL2,'^[0-9]*$'))
 );

插入时,您只是在值中没有id:

INSERT INTO TEST_TABLE(NAME, PERSONAL_ID_NUM)
VALUES('JOHN', '12345678901');

该文件指出了关于身份栏

的表现的以下内容
  

毫不奇怪,基于触发器的测试比其他测试表现更差。直接使用序列和12c标识列可以得到可比较的结果,这通常比使用触发器填充ID列快一个数量级。

注意 - 并更新:

您还提到ID很没有差距很重要。如果这是一个硬性要求,则序列和标识列(内部使用序列)不保证。您可以通过NO CACHE对序列进行最小化。

然而,对于guaratee没有空白,你需要使用序列化,线程安全的机制,如

  • 拥有一个包含单个记录(保留最后一个数字)的表,该记录在锁定,增加,然后提交整个事务的一部分之后分配一个数字。这样就会产生性能影响,特别是如果你有长时间运行的事务
  • 使用包含所有ID的表(可以逐块使用),标记为“pending”然后“used”(两次更新和一次短锁)。这也具有性能影响,取决于ID的设置频率