How to change column identify from sequence to GENERATED ALWAYS with data - oracle

as my title, I want to change my identity column by sequence to GENERATED ALWAYS.
For ex, I have a table like this:
CREATE SEQUENCE DPT.Deposit_SEQ
START WITH 1
INCREMENT BY 10
NOCACHE
NOCYCLE;
CREATE TABLE DPT.TEST(
Id NUMBER(10)DEFAULT DPT.Deposit_SEQ.nextval NOT NULL
,Code VARCHAR2(20),
CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
Insert into DPT.TEST (ID, CODE) values (1,'ABC');
COMMIT;
Now, I want to change from sequence to GENERATED ALWAYS like this:
Id NUMBER(10) GENERATED ALWAYS AS IDENTITY START WITH 6
INCREMENT BY 10
NOCACHE
NOCYCLE;
I tried by create one more column and drop old column but failed. How can I do that?
Thanks!

"But failed" is not an Oracle error and is difficult to debug.
Anyway, it works for me:
Create table and a sequence, insert some rows:
SQL> CREATE SEQUENCE Deposit_SEQ START WITH 1 INCREMENT BY 10 NOCACHE NOCYCLE;
Sequence created.
SQL> CREATE TABLE TEST
2 (
3 Id NUMBER (10) DEFAULT Deposit_SEQ.NEXTVAL NOT NULL,
4 Code VARCHAR2 (20),
5 CONSTRAINT PK_TEST PRIMARY KEY (ID)
6 );
Table created.
SQL>
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (1, 'ABC');
1 row created.
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (3, 'DEF');
1 row created.
SQL> SELECT * FROM test;
ID CODE
---------- --------------------
1 ABC
3 DEF
Drop current primary key column (ID) and add a new, identity column:
SQL> ALTER TABLE test
2 DROP COLUMN id;
Table altered.
SQL> ALTER TABLE test
2 ADD id NUMBER GENERATED ALWAYS AS IDENTITY START WITH 6;
Table altered.
SQL> SELECT * FROM test;
CODE ID
-------------------- ----------
ABC 6
DEF 7
SQL> ALTER TABLE test ADD CONSTRAINT pk_test PRIMARY KEY (id);
Table altered.
SQL>
As you can see, no problem.

Related

Oracle - Foreign Key references different tables different schemas

I have problem with Enforcing Referential Integrity to a new table.
There are different tables in different schemas, each one has its primary key:
schema1.table1
schema2.table2
schema3.table3
I want to create a new table, which among other information and its primary id, has a column "reference_schema" and a column "reference_id".
I want the column "referencing id" to reference the id on the relevant table, that is of the "reference_schema"="schema1" to reference the primary key schema1.table1.id.
The primary keys on the 3 tables, aren't unique in a UNION.
I have tried synthesizing a primary key in a UNION ALL view, but Oracle does not enforce view constraints.
It is not the different schema that causes problems, but the fact that you can't create a foreign key constraint which would reference two (or more) different tables.
I mean, you can do it, using out-of-line constraint syntax, but that just won't work. Why? Because - if that value doesn't exist in all referenced tables, constraint will be violated.
create table new_table
(id number constraint pk_newtab primary key,
ref_schema varchar2(30),
ref_id number,
--
constraint fk_newtab_s1 foreign key (ref_id) references schema1.table1 (id),
constraint fk_newtab_s2 foreign key (ref_id) references schema2.table2 (id)
);
A simple example is Scott's sample schema (there is department number 10, but no employee has that EMPNO):
SQL> create table test
2 (id number,
3 constraint fk1 foreign key (id) references scott.dept (deptno),
4 constraint fk2 foreign key (id) references scott.emp (empno)
5 );
Table created.
SQL> insert into test (id) values (10);
insert into test (id) values (10)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.FK2) violated - parent key not found
SQL>
So, what can you do? Use a trigger. Something like this:
SQL> create or replace trigger trg_test
2 before insert or update on test
3 for each row
4 declare
5 l_cnt number;
6 begin
7 select deptno into l_cnt
8 from dept
9 where deptno = :new.id;
10
11 exception
12 when no_data_found then
13 begin
14 select empno into l_cnt
15 from emp
16 where empno = :new.id;
17
18 exception
19 when no_data_found then
20 raise_application_error(-20000, 'Foreign key does not exist in any referenced table');
21 end;
22 end;
23 /
Trigger created.
Testing:
SQL> insert into test (id) values (10); --> this is ACCOUNTING
1 row created.
SQL> insert into test (id) values (7369); --> this is SMITH
1 row created.
SQL> insert into test (id) values (99); --> this doesn't exist in any table
insert into test (id) values (99)
*
ERROR at line 1:
ORA-20000: Foreign key does not exist in any referenced table
ORA-06512: at "SCOTT.TRG_TEST", line 17
ORA-04088: error during execution of trigger 'SCOTT.TRG_TEST'
SQL>
From Oracle 12, you can use virtual columns and put the constraints on the virtual column.
For example, if you have the tables:
CREATE TABLE table1 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table2 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table3 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
Then you can create your table as:
CREATE TABLE new_table(
id NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
reference_table VARCHAR2(30)
CHECK (reference_table IN ('table1', 'table2', 'table3')),
reference_id NUMBER
NOT NULL,
t1_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table1' THEN reference_id END
)
REFERENCES table1(id),
t2_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table2' THEN reference_id END
)
REFERENCES table2(id),
t3_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table3' THEN reference_id END
)
REFERENCES table3(id)
);
Note: If you want to change from different tables in the same schema to the same table in different schemas then just update the foreign key constraint to point to the correct location.
db<>fiddle here

Oracle: can I create a constraint that checks a value within a group

Thanks in advance for your help with this. In Oracle, is it possible to create a constraint so that there can only be one 'leader' per group:
How can I create a rule that prevents an additional 'leader' from being inserted if one already exists in a group?
Does this make sense? A function-based unique index:
SQL> create table test (col1 varchar2(10), col2 varchar2(10), col3 varchar2(10));
Table created.
SQL> create unique index ui1t on test (case when col2 = 'leader' then col1||col2 end);
Index created.
Testing:
SQL> insert into test values ('group1', 'leader', 'joe');
1 row created.
SQL> insert into test values ('group1', null , 'diane');
1 row created.
SQL> insert into test values ('group1', null , 'john');
1 row created.
SQL> insert into test values ('group1', null , 'diane');
1 row created.
SQL> insert into test values ('group1', 'leader', 'mike'); --> another LEADER for GROUP1
insert into test values ('group1', 'leader', 'mike')
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.UI1T) violated
SQL> insert into test values ('group1', 'leader', null); --> another LEADER for GROUP1
insert into test values ('group1', 'leader', null)
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.UI1T) violated
SQL>

How add autoincrement to existing table in Oracle

Is there any ways to add autoincrement to primary key in already existing table in Oracle 12c. May be with ALTER TABLE function or smth, I mean without triggers and sequences.
As far as I can tell, you can not "modify" existing primary key column into a "real" identity column.
If you want to do that, you'll have to drop the current primary key column and then alter table and add a new identity column.
Workaround is to use a sequence (or a trigger), but - you said you don't want to do that. Anyway, if you decide to use it:
SQL> create table test
2 (id number constraint pk_test primary key,
3 name varchar2(10));
Table created.
SQL> insert into test values (1, 'LF');
1 row created.
SQL> create sequence seq_test start with 2;
Sequence created.
SQL> alter table test modify id default seq_test.nextval;
Table altered.
SQL> insert into test (name) values ('BF');
1 row created.
SQL> select * from test;
ID NAME
---------- ----------
1 LF
2 BF
SQL>
Or, with dropping current primary key column (note that it won't work easy if there are foreign keys involved):
SQL> alter table test drop column id;
Table altered.
SQL> alter table test add id number generated always as identity;
Table altered.
SQL> select * From test;
NAME ID
---------- ----------
LF 1
BF 2
SQL> insert into test (name) values ('test');
1 row created.
SQL> select * From test;
NAME ID
---------- ----------
LF 1
BF 2
test 3
SQL>

In Oracle, does the unique constraint include an index implicitly?

this question is for performance issue,
For example, if I would add a unique constraint such as:
ALTER TABLE Staffs ADD CONSTRAINT test UNIQUE (Company_Name, Staff_ID);
should I add a unique index for performance issue?
CREATE UNIQUE INDEX test2 ON Staffs (Company_Name, Staff_ID);
For Primary key, I can see there must be a corresponding index in dba_indexes system table,
but I have not seen the equivalent for the case unique constraint
"I have not seen the equivalent for the case unique constraint"
Hmmmm, are you sure?
SQL> create table t23
2 (id number
3 , col1 date)
4 /
Table created.
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_UK UNIQUE
SQL>
Note that we can use an existing index, and it doesn't have to be unique. But this means the index name might not match the constraint name (this would also work for primary keys):
SQL> alter table t23 drop constraint t23_uk;
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
no rows selected
SQL> create index t23_idx on t23(id)
2 /
Index created.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_IDX NONUNIQUE
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL>
Does the non-unique index enforce the unique constraint? Yes it does:
SQL> insert into t23 values (1, sysdate)
2 /
1 row created.
SQL> r
1* insert into t23 values (1, sysdate)
insert into t23 values (1, sysdate)
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated
SQL> drop index t23_idx
2 /
drop index t23_idx
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
SQL>
We can check the data dictionary to see which index is associated with a constraint:
SQL> select constraint_name, constraint_type, index_name
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C INDEX_NAME
------------------------------ - ------------------------------
T23_UK U T23_IDX
SQL>

Auto Increment for Oracle

I need to create a sequence and a trigger to auto-increment the primary key on a table but I have no idea on how to do it.
Create the table and the sequence
SQL> create table staff (
2 emp_id number primary key,
3 staff_name varchar2(100)
4 );
Table created.
SQL> create sequence emp_id_seq;
Sequence created.
Now, you can create a trigger that uses the sequence to populate the primary key
SQL> create trigger trg_emp_id
2 before insert on staff
3 for each row
4 begin
5 select emp_id_seq.nextval
6 into :new.emp_id
7 from dual;
8 end;
9 /
Trigger created.
Now, when you insert data, you woon't need to specify the EMP_ID column-- it will automatically be populated by the trigger
SQL> insert into staff( staff_name ) values ('Justin');
1 row created.
SQL> select * from staff;
EMP_ID STAFF_NAME
---------- --------------------
1 Justin
Read this, Beautiful article.
how sequence [auto increment in oracle]
syntax
Create sequence sequence_name
start with value
increment by value
minvalue value
maxvalue value;
example
SQL> create table emp (
emp_id number(10),
fname varchar2(25),
lname varchar2(25),
constraint pk_emp_id PRIMARY KEY(emp_id)
);
SQL> Create sequence emp_sequence
start with 1
increment by 1
minvalue 1
maxvalue 10000;
SQL> insert into emp (emp_id,fname,lname) values(emp_sequence.nextval,'Darvin','Johnson');
SQL> insert into emp (emp_id,fname,lname) values(emp_sequence.nextval,'Mig','Andrews');
SQL> insert into emp (emp_id,fname,lname) values(emp_sequence.nextval,'Alex','Martin');
SQL> insert into emp (emp_id,fname,lname) values(emp_sequence.nextval,'Jon','paul');
SQL> insert into emp (emp_id,fname,lname) values(emp_sequence.nextval,'Yatin','Bones');
in emp_sequence.nextval where emp_sequence is the name of sequence we created above and nextval is a function that is used to assign the next number from emp_sequence to emp_id column in emp table.
SQL> select * from emp;
EMP_ID FNAME LNAME
---------- ------------------------- -------------------------
1 Darvin Johnson
2 Mig Andrews
3 Alex Martin
4 Jon paul
5 Yatin Bones
Try this:
create sequence seq_EmpID start with 1 increment by 1
insert into Emp_Table values(seq_EmpID.nextval,'Ram')
I am not sure which version of Oracle you are using, but the following will work in 19c:
create table staff (
emp_id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
staff_name varchar2(100)
);
https://docs.oracle.com/en/database/other-databases/nosql-database/19.3/java-driver-table/creating-tables-identity-column.html
The command above creates a system sequence that is automatically employed to populate the key value. you cannot drop the sequence created as it is a system sequence, but because of the dependency on the column when the table is dropped and the recycle bin purged it is removed.
Very good question!!
Probably sequence can be used in this way - also, I am not sure if there really is a difference :
CREATE SEQUENCE emp_id_seq MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 10;
First creating the table :
sql-> create table item(id int primary key, name varchar(25),qty int, price int);
Now we want to make auto increment sequence to the first column i.e. id
sql-> CREATE SEQUENCE id MINVALUE 1 START WITH 1 CACHE 10; //system saves the last 10 items in temp memory
This will create auto increment.
Now we are inserting data:
sql-> insert into item VALUES(id.nextval,'ddcd',2,4);
sql-> insert into item VALUES(id.nextval,'ddcd',676,4);
Finally Displaying the table :
SQL> select * from item;
ID NAME QTY PRICE
1 ddcd 2 4
2 ddcd 676 4
If you use a sequence for several tables, because the value of the sequence is inconsistent example:
we have two tables emp and depeartement:
If I use the sequence on emp I would have: ID_dept = 6 because the 5 is already used in the other table.
example :
SQL> insert into emp values(masequence.nextval,'aaa');
1 ligne crÚÚe.
SQL> insert into departement values(masequence.nextval,'aaa');
1 ligne crÚÚe.
SQL> select * from emp;
ID_EMP NOM_EMP
---------- -------------------------
5 aaa
SQL> select * from departement;
ID_DEPT NOM_DEPT
---------- ----------
6 aaa
SQL>

Resources