Difference between Oracle sequence last number and max id inserted - oracle

I'm working on a application used by multiple users. They can insert, delete and update rows in the database which fires triggers what write into log tables. The problem is that the difference between the maximum id inserted in the log table and the last number generated by the sequences used by the trigger is changing continously. Sometimes an primary key exception is generated because the the sequence generate values that are already inserted in the table.
CREATE OR REPLACE
TRIGGER EVALUACION.TCALIF_DEL
AFTER DELETE ON EVALUACION.CALIFICACIONES FOR EACH ROW
BEGIN
INSERT INTO LOG_CALIFICACIONES (ID_BITACORA, ID_EVALUACION, ANIO, CALIFICACION, OBSERVACION, USUARIO, FECHA_HORA, TIPO_OPERACION_BD)
SELECT SEQ_CALIF.NEXTVAL, :OLD.ID_EVALUACION, :OLD.ANIO, :OLD.CALIFICACION, :OLD.OBSERVACION, :OLD.USUARIO, :OLD.FECHA_HORA, 'D' FROM DUAL;
END;
CREATE OR REPLACE
TRIGGER EVALUACION.TCALIF_INS
AFTER INSERT ON EVALUACION.CALIFICACIONES FOR EACH ROW
BEGIN
INSERT INTO LOG_CALIFICACIONES (ID_BITACORA, ID_EVALUACION, ANIO, CALIFICACION, OBSERVACION, USUARIO, FECHA_HORA, TIPO_OPERACION_BD)
SELECT SEQ_CALIF.NEXTVAL, :OLD.ID_EVALUACION, :OLD.ANIO, :OLD.CALIFICACION,:OLD.OBSERVACION, :OLD.USUARIO, :OLD.FECHA_HORA, 'I' FROM DUAL;
END;
CREATE OR REPLACE
TRIGGER EVALUACION2010.TCALIF_UPD
AFTER UPDATE ON EVALUACION.CALIFICACIONES FOR EACH ROW
BEGIN
INSERT INTO LOG_CALIFICACIONES (ID_BITACORA, ID_EVALUACION, ANIO, CALIFICACION, OBSERVACION, USUARIO, FECHA_HORA, TIPO_OPERACION_BD)
SELECT SEQ_CALIF.NEXTVAL, :OLD.ID_EVALUACION, :OLD.ANIO, :OLD.CALIFICACION, :OLD.OBSERVACION, :OLD.USUARIO, :OLD.FECHA_HORA, 'U' FROM DUAL; END;
The code for the sequence is:
CREATE SEQUENCE "EVALUACION"."SEQ_CALIF"
MINVALUE 1
MAXVALUE 999999999999999999999999999
INCREMENT BY 1
START WITH 11114992
CACHE 20
NOORDER
NOCYCLE
NOPARTITION;

Related

Error unique constraint and during execution of trigger oracle

I have form in which user add information of new born baby with his/her head family name. When add information into table then getting following errors
ORA-00001: unique constraint (PK) violated
ORA-06512: at trigger_name, line 21
ORA-04088: error during execution of trigger
Trigger:
CREATE OR REPLACE TRIGGER "DB_NAME"."TRG_NBB"
AFTER INSERT ON baby
FOR EACH ROW
WHEN (new.status = 'A') DECLARE
v_1 tab_1.col_1%type;
v_2 tab_2.col_2%type;
v_3 tab_2.col_3%type;
v_4 tab_2.col_4%type;
v_5 tab_2.col_5%type;
v_6 date;
newmofid number;
BEGIN
select max(nvl(col_2,0))+1 into newmofid from tab_2;
SELECT distinct col_1,col_2,to_char(col,'DD-MM-YYYY') INTO v_1,v_2,v_6
from table
where tcid = :new.tcid;
SELECT col_4,col_5,col_3 into v_4,v_5,v_3
from tab_2
where col_1 = v_1
and col_2 = v_2;
INSERT INTO tab_2 (all_columns)
VALUES(variable_names);
DBMS_OUTPUT.PUT_LINE('New Born Baby successfully added to member table');
END trg_nbb;
/
ALTER TRIGGER "DB_NAME"."TRG_NBB" ENABLE;
When I execute this sql query It's take 4 to 5 seconds and increment in values very quickly
select max(nvl(col_2,0))+1 into newmofid from tab_2;
Result:
6030819791
Again execute takes 3 to 4 seconds
Result:
6030819798
How to solve this problem?
Thanks
I suspect it is MAX + 1 that causes problems:
select max(nvl(col_2,0))+1 into newmofid from tab_2;
Such a principle is in most cases wrong and will fails, especially in a multi-user environment where two (or more) users at the same time fetch the same MAX + 1 value, do some processing, and - at the time of insert - one of them succeeds (because it is the first), but the rest of them fail because such a value already exists in the table.
I suggest you switch to a sequence, e.g.
create sequence seq_baby;
and then, in your form, do
select seq_baby.nextval into newmofid from dual;

insert multiple row into table using select however table has primery key in oracle SQL [duplicate]

This question already has answers here:
How to create id with AUTO_INCREMENT on Oracle?
(18 answers)
Closed 8 years ago.
I am facing issue while inserting multiple row in one go into table because column id has primary key and its created based on sequence.
for ex:
create table test (
iD number primary key,
name varchar2(10)
);
insert into test values (123, 'xxx');
insert into test values (124, 'yyy');
insert into test values (125, 'xxx');
insert into test values (126, 'xxx');
The following statement creates a constraint violoation error:
insert into test
(
select (SELECT MAX (id) + 1 FROM test) as id,
name from test
where name='xxx'
);
This query should insert 3 rows in table test (having name=xxx).
You're saying that your query inserts rows with primary key ID based on a sequence. Yet, in your insert/select there is select (SELECT MAX (id) + 1 FROM test) as id, which clearly is not based on sequence. It may be the case that you are not using the term "sequence" in the usual, Oracle way.
Anyway, there are two options for you ...
Create a sequence, e.g. seq_test_id with the starting value of select max(id) from test and use it (i.e. seq_test_id.nextval) in your query instead of the select max(id)+1 from test.
Fix the actual subselect to nvl((select max(id) from test),0)+rownum instead of (select max(id)+1 from test).
Please note, however, that the option 2 (as well as your original solution) will cause you huge troubles whenever your code runs in multiple concurrent database sessions. So, option 1 is strongly recommended.
Use
insert into test (
select (SELECT MAX (id) FROM test) + rownum as id,
name from test
where name='xxx'
);
as a workaround.
Of course, you should be using sequences for integer-primary keys.
If you want to insert an ID/Primary Key value generated by a sequence you should use the sequence instead of selecting the max(ID)+1.
Usually this is done using a trigger on your table wich is executed for each row. See sample below:
CREATE TABLE "MY_TABLE"
(
"MY_ID" NUMBER(10,0) CONSTRAINT PK_MY_TABLE PRIMARY KEY ,
"MY_COLUMN" VARCHAR2(100)
);
/
CREATE SEQUENCE "S_MY_TABLE"
MINVALUE 1 MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 10 NOCACHE ORDER NOCYCLE NOPARTITION ;
/
CREATE OR REPLACE TRIGGER "T_MY_TABLE"
BEFORE INSERT
ON
MY_TABLE
REFERENCING OLD AS OLDEST NEW AS NEWEST
FOR EACH ROW
WHEN (NEWEST.MY_ID IS NULL)
DECLARE
IDNOW NUMBER;
BEGIN
SELECT S_MY_TABLE.NEXTVAL INTO IDNOW FROM DUAL;
:NEWEST.MY_ID := IDNOW;
END;
/
ALTER TRIGGER "T_MY_TABLE" ENABLE;
/
insert into MY_TABLE (MY_COLUMN) values ('DATA1');
insert into MY_TABLE (MY_COLUMN) values ('DATA2');
insert into MY_TABLE (MY_ID, MY_COLUMN) values (S_MY_TABLE.NEXTVAL, 'DATA3');
insert into MY_TABLE (MY_ID, MY_COLUMN) values (S_MY_TABLE.NEXTVAL, 'DATA4');
insert into MY_TABLE (MY_COLUMN) values ('DATA5');
/
select * from MY_TABLE;

Truncate data and if insert new row column increment from 1

I have table with two rows which one ID with auto increment and there are much row last number ID is 89. And then I truncate data/row in the table. And then I insert row again.
But number ID from 90 not from 1 (one). If in mysql if I truncate data in table auto increment start from 1 (one) again. So how in oracle I want to ID autoincrement from one again. Thanx.
Below step when I create table:
// create table;
CREATE TABLE tes (
id NUMBER NULL,
ip_address varchar2(25) NOT NULL
PRIMARY KEY (id)
);
// and create increment;
CREATE SEQUENCE tes_sequence START WITH 1 INCREMENT BY 1;
// and create trigger;
CREATE OR REPLACE TRIGGER tes_trigger
BEFORE INSERT
ON tes
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT tes_sequence.nextval INTO :NEW.ID FROM dual;
END;
Oracle sequence is a separate object and is not connected with table. If you need to start sequence after truncating a table you need to alter the sequence. Have a look here: How do I reset a sequence in Oracle?

Using sequential values for the primary key in an INSERT query

How can I write an insert query for an Oracle database which has a sequential primary key so that the insert statement automatically takes the next number in the sequence?
INSERT INTO LD_USER_ROLE(USER_ROLE_ID,INS_USER,INS_DATE, USERNAME)
VALUES (100, 'sp22',to_date('2003/05/03 21:02:44','yyyy/mm/dd hh24:mi:ss'),'JOHN BARRY', )
In the above statement I have hardcoded the value of 100 for the key 'USER_ROLE_ID' but I'd like to alter this as explained in the first paragraph.
Why don't you just create a trigger for your sequence like this:
Sequence:
CREATE SEQUENCE LD_USER_ROLE_SEQ
INCREMENT BY 1 START WITH 1 NOMAXVALUE NOMINVALUE NOCYCLE NOCACHE NOORDER
Trigger:
CREATE TRIGGER LD_USER_ROLE_INSERT BEFORE INSERT ON LD_USER_ROLE
REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
BEGIN
SELECT LD_USER_ROLE_SEQ.NEXTVAL INTO :NEW.USER_ROLE_ID FROM DUAL;
END;
The trigger will automatically get the next value/id on every insert (like auto_increment in mysql).
Apart from using a trigger, you can use a sequence directly in the insert statement:
CREATE SEQUENCE LD_USER_ROLE_SEQ;
INSERT INTO LD_USER_ROLE
(USER_ROLE_ID,INS_USER,INS_DATE, USERNAME)
VALUES
(ld_user_role_seq.nextval, 'sp22',to_date('2003/05/03 21:02:44','yyyy/mm/dd hh24:mi:ss'),'JOHN BARRY', )

Bulk Update from one table to another

So I tried the bulk update in order to copy values from uemte_id column in pp_terminal table to uemte_id column (null at start) in mm_chip table. These two tables have no columns in common.This is what I used:
declare
type ue_tab is table of
pp_terminal.uemte_id%type;
ue_name ue_tab;
cursor c1 is select uemte_id from pp_terminal;
begin
open c1;
fetch c1 bulk collect into ue_name;
close c1;
-- bulk insert
forall indx in ue_name.first..ue_name.last
update mm_chip set uemte_id = ue_name(indx);
end;
/
And this is the error message I get:
Error report:
ORA-00001: unique constraint (DPOWNERA.IX_AK7_MM_CHIP) violated
ORA-06512: at line 13
00001. 00000 - "unique constraint (%s.%s) violated"
*Cause: An UPDATE or INSERT statement attempted to insert a duplicate key.
For Trusted Oracle configured in DBMS MAC mode, you may see
this message if a duplicate entry exists at a different level.
*Action: Either remove the unique restriction or do not insert the key.
Do you see any obvious misstakes?
What you're trying to do is:
select a row from the first table
update every row in the second table with that value
select another row from the first table
update every row in the second table with that value
and so forth until the loop finishes
I'm guessing that's not what you really want to do. It's failing because you have a unique constraint so you're not allowed to have multiple rows in the second table with the same value.
Below is one way to update each row of one table based on the value of an arbitrary row in a second table, without reusing any rows from the second table. It would perform better if you could do it entirely in SQL, but I couldn't come up with a way to do that.
CREATE TABLE test4 AS
(SELECT LEVEL AS cola, CAST(NULL AS number) AS colb
FROM DUAL
CONNECT BY LEVEL <= 100);
CREATE TABLE test5 AS
(SELECT 100 + LEVEL AS colc
FROM DUAL
CONNECT BY LEVEL <= 99);
DECLARE
CURSOR cur_test4 IS
SELECT *
FROM test4
FOR UPDATE ;
CURSOR cur_test5 IS
SELECT * FROM test5;
r_test5 cur_test5%ROWTYPE;
BEGIN
OPEN cur_test5;
FOR r_test4 IN cur_test4 LOOP
FETCH cur_test5 INTO r_test5;
IF cur_test5%NOTFOUND THEN
EXIT;
END IF;
UPDATE test4
SET colb = r_test5.colc
WHERE CURRENT OF cur_test4;
END LOOP;
CLOSE cur_test5;
END;

Resources