我创建了一个表,一个序列和一个触发器。我用正确的数据添加第一条记录。在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;
答案 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
- 但不是两个):
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没有空白,你需要使用序列化,线程安全的机制,如