Insert All with Sequence.nextVal Generates Unique Constraint violation [duplicate] - sql

This question already has answers here:
Inserting multiple rows with sequence in Oracle
(5 answers)
Closed 4 years ago.
Why does this query throw an error:
Error report -
ORA-00001: unique constraint (ON24MASTER.LANGUAGE_CODE_PK) violated
Query
INSERT ALL
INTO LANGUAGE_CODE(language_code_id,label,language_cd,country_cd,is_elite)
VALUES(SEQ_LANGUAGE_CODE_ID.NEXTVAL,'Abkhazian','ab',NULL,'N')
INTO LANGUAGE_CODE(language_code_id,label,language_cd,country_cd,is_elite)
VALUES(SEQ_LANGUAGE_CODE_ID.NEXTVAL,'Afar','aa',NULL,'N')
INTO LANGUAGE_CODE(language_code_id,label,language_cd,country_cd,is_elite)
VALUES(SEQ_LANGUAGE_CODE_ID.NEXTVAL,'Afrikaans','af',NULL,'N')
INTO LANGUAGE_CODE(language_code_id,label,language_cd,country_cd,is_elite)
VALUES(SEQ_LANGUAGE_CODE_ID.NEXTVAL,'Akan','ak',NULL,'N')
SELECT 1 FROM DUAL;
Considering select seq_language_code_id.nextval from dual; = 198 and the latest id in db is 180;
What is wrong ? can I not use insert all with .nextVal ?

Nope, you can't do it with INSERT ALL. Have a look at what's going on:
SQL> create sequence seqa;
Sequence created.
SQL> create table test (id number);
Table created.
SQL> insert all
2 into test values (seqa.nextval)
3 into test values (seqa.nextval)
4 into test values (seqa.nextval)
5 into test values (seqa.nextval)
6 select * from dual;
4 rows created.
SQL> select * From test;
ID
----------
1
1
1
1
SQL>
See? All NEXTVALs are just the same, which - in your case - leads to a primary key violation, which means that you'll have to run separate INSERT INTO statements:
SQL> insert into test values (seqa.nextval);
1 row created.
SQL> insert into test values (seqa.nextval);
1 row created.
SQL> insert into test values (seqa.nextval);
1 row created.
SQL> select * From test;
ID
----------
1
1
1
1
2
3
4
7 rows selected.
SQL>

Related

Trying to insert multiple rows in my table in SQL.Always showing SQL Command not ended properly [duplicate]

This question already has answers here:
Best way to do multi-row insert in Oracle?
(9 answers)
Closed 1 year ago.
I am trying to insert multiple rows into my table using the below query : INSERT INTO TABLE2(ID) VALUES(1),(2) .It is showing SQL Command Not Ended.
Is it some syntacital error?I have rechecked but still not clear what's going wrong.
Invalid syntax, of course. But, here are 3 options that work.
SQL> create table table2(id number);
Table created.
SQL>
SQL> insert into table2(id) values(1);
1 row created.
SQL> insert into table2(id) values(2);
1 row created.
SQL>
SQL> insert all
2 into table2(id) values (1)
3 into table2(id) values (2)
4 select * from dual;
2 rows created.
SQL>
SQL> insert into table2(id)
2 select 1 from dual
3 union all
4 select 2 from dual;
2 rows created.
SQL>

Create Auto Sequence text and number in oracle 11g

How I do create column ID with value JASG1?
I am only find example like this :
select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job
Although what you wrote probably works (if there's a sequence named MTJ_ID_SEQ, you have a privilege to select from it; the same goes for the TALEND_JOB table), I'd say that it isn't what you should use.
Here's why: I'll create a table and a sequence. Table will be pre-populated with some IDs (just to put something in there).
SQL> create sequence mtj_id_seq;
Sequence created.
SQL> create table talend_job as
2 select rownum id from dept;
Table created.
SQL> select * from talend_job;
ID
----------
1
2
3
4
OK; 4 rows so far. Now, run your SELECT:
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG1
JASG2
JASG3
JASG4
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from talend_job;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG5
JASG6
JASG7
JASG8
SQL>
See? You didn't get only 1 JASGx value, but as many as number of rows in the TALEND_JOB table. If there was a million rows, you'd get a million JASGx rows as well.
Therefore, maybe you meant to use DUAL table instead? E.g.
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG9
SQL> select 'JASG'||to_char(mtj_id_seq.nextval) from dual;
'JASG'||TO_CHAR(MTJ_ID_SEQ.NEXTVAL)
--------------------------------------------
JASG10
SQL>
See? Only one value.
Also, notice that sequences will provide unique values, but you can't rely on them being gapless.
As you mentioned "how to create column ID" - one option is to use a trigger. Here's an example:
SQL> create table talend_job (id varchar2(20), name varchar2(20)
Table created.
SQL> create or replace trigger trg_bi_tj
2 before insert on talend_job
3 for each row
4 begin
5 :new.id := 'JASG' || mtj_id_seq.nextval;
6 end;
7 /
Trigger created.
Let's insert some names; IDs should be auto-populated by the trigger:
SQL> insert into talend_job (name) values ('littlefoot');
1 row created.
SQL> insert into talend_job (name) values ('Ishak');
1 row created.
SQL> select * From talend_job;
ID NAME
-------------------- --------------------
JASG11 littlefoot
JASG12 Ishak
SQL>
OK then; now you have some more info - read and think about it.
By the way, what is the "compiler-errors" tag used for? Did you write any code and it failed? Perhaps you'd want to share it with us.

Select records which have two digits on the left and four digits on the right side in Oracle

Table with example data:
ID ANPR_TEXT
-------------
1 16AH22551
2 DL8CM8797
In this example I' like to select the row with 16AH22551.
I tried:
select ANPR_TEXT,
to_number(regexp_substr(ANPR_TEXT,'\d+$'))
from TXN_SPEED_CAM;
But it didn't work. Could anyone help, please!
I need 16AH22551
Update OP wants at least count to match, not exact match.
From documentation on POSIX Metacharacters in Oracle Database Regular Expressions
{m,}
Interval—At Least Count
Matches at least m occurrences of the preceding subexpression.
The expression a{3,} matches the strings aaa and aaaa, but does not
match aa.
So, you need to use {m, } expression which means it will match at least m occurrences. REGEXP_LIKE(anpr_text, '[[:digit:]]{2,}[[:alpha:]]{2,}[[:digit:]]{4,}')
For example,
SQL> CREATE TABLE t(ID NUMBER, anpr_text VARCHAR2(20));
Table created.
SQL>
SQL> INSERT INTO t VALUES(1, '16AH22551');
1 row created.
SQL> INSERT INTO t VALUES(2, 'DL8CM8797');
1 row created.
SQL> INSERT INTO t VALUES(3, '123ABC8797 ');
1 row created.
SQL> INSERT INTO t VALUES(4, 'HR29AE5806 ');
1 row created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM t
2 WHERE REGEXP_LIKE(anpr_text, '[[:digit:]]{2,}[[:alpha:]]{2,}[[:digit:]]{4,}');
ID ANPR_TEXT
---------- --------------------
1 16AH22551
3 123ABC8797
4 HR29AE5806
SQL>
For an exact pattern match:
If you have a fixed pattern of first two digits, then two alphabets and then at least 4 digits, then you could do a pattern match using REGEXP_LIKE.
For example,
SQL> CREATE TABLE t(ID NUMBER, anpr_text VARCHAR2(20));
Table created.
SQL>
SQL> INSERT INTO t VALUES(1, '16AH22551');
1 row created.
SQL> INSERT INTO t VALUES(2, 'DL8CM8797');
1 row created.
SQL> INSERT INTO t VALUES(3, '123ABC8797');
1 row created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM t
2 WHERE REGEXP_LIKE(anpr_text, '[[:digit:]]{2}[[:alpha:]]{2}[[:digit:]]{4}');
ID ANPR_TEXT
---------- --------------------
1 16AH22551
SQL>

Returning the value of identity column after insertion in Oracle

How do I return the value of an identity column (id) in Oracle 12c after insertion? Seems like most of the approaches out there uses sequence to get back the id of the inserted item.
Simply use the RETURNING clause.
For example -
RETURNING identity_id INTO variable_id;
Test case -
SQL> set serveroutput on
SQL> CREATE TABLE t
2 (ID NUMBER GENERATED ALWAYS AS IDENTITY, text VARCHAR2(50)
3 );
Table created.
SQL>
SQL> DECLARE
2 var_id NUMBER;
3 BEGIN
4 INSERT INTO t
5 (text
6 ) VALUES
7 ('test'
8 ) RETURNING ID INTO var_id;
9 DBMS_OUTPUT.PUT_LINE('ID returned is = '||var_id);
10 END;
11 /
ID returned is = 1
PL/SQL procedure successfully completed.
SQL>
SQL> select * from t;
ID TEXT
---------- --------------------------------------------
1 test
SQL>

Oracle Constraints

I am working on a small school project using oracle database. I have created some tables and two of them are Mobile (Mobile_Number,Status_Flag) Status_Flag shows if a number is active or not and there is another table Owner_Mobile(Owner_Id FK,Mobile_ID FK). Now I should write a Constraint that prohibits the insert operation if the corresponding Status_Flag is N for the specified number. I tried to make it using sub query but this is not possible.
the constrain should be applied to OWNER_MOBILE table of course. For example if I say: INSERT INTO OWNER_MOBILE(25541,042536) the constrain should check the Mobile table and see if the Mobile 042536 is active or not . If the number is not active the insert statement should generate a error
You can use the trigger or another PL/SQL API for this but you should take into account ACID transaction principles. Let's consider the case when flag value = 0 should prevent insertion:
SQL> create table mobile (mobile_id int primary key, flag int)
2 /
SQL> create table owner_mobile(owner_id int,
2 mobile_id int references mobile(mobile_id))
3 /
SQL> insert into mobile values (1,1)
2 /
SQL> commit
2 /
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id;
10
11 if l_flag = 0 then
12 raise_application_error(-20000, 'Unavalable mobile');
13 end if;
14 end;
15 /
In the code above I simply select flag and rely on the retrieved value - I don't care of ACID.
In the first transaction I update flag value but don't commit:
SQL> update mobile set flag = 0 where mobile_id = 1;
In the second transaction I insert into owner_mobile and get the success:
SQL> insert into owner_mobile values(1,1);
1 row inserted.
Next, I commit the first transaction and later - the second one. What I get then:
SQL> select * from mobile;
MOBILE_ID FLAG
---------- ----------
1 0
SQL> select * from owner_mobile;
OWNER_ID MOBILE_ID
---------- ----------
1 1
Seems this is not what I expect.
I can use select for update to prevent inconsistent behavoiur:
SQL> update mobile set flag = 1;
1 row updated.
SQL> delete from owner_mobile;
1 row deleted.
SQL> commit;
SQL> create or replace trigger
2 tr_owner_mobile
3 before insert on owner_mobile
4 for each row
5 declare
6 l_flag mobile.flag%type;
7 begin
8 select flag into l_flag
9 from mobile where mobile_id = :new.mobile_id
10 for update;
11
12 if l_flag = 0 then
13 raise_application_error(-20000, 'Unavalable mobile');
14 end if;
15 end;
16 /
Now do the same:
SQL> update mobile set flag = 0 where mobile_id = 1;
1 row updated.
Second transaction is waiting because parent row is locked:
SQL> insert into owner_mobile values(1,1);
After commit in first transaction I get in the second one:
SQL> insert into owner_mobile values(1,1);
insert into owner_mobile values(1,1)
*
error in line 1:
ORA-20000: Unavalable mobile
ORA-06512: at "SCOTT.TR_OWNER_MOBILE", line 9
ORA-04088: error in trigger 'SCOTT.TR_OWNER_MOBILE'
So whatever you do to achieve requirements you will have to consider transaction isolation.