How add autoincrement to existing table in Oracle - 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>

Related

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

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.

Altering table property to default when NULL only for new inserts

Is there any way in Oracle that we can set Default column value when NULL only for New inserts? I don't want to change the Existing records if they have NULL.
I want to do this at table level. Not with NVL insert logic.
As far as I know, if you alter the table and set a default value for a column, it should only affect new records which would come in via an insert, not existing records.
ALTER TABLE yourTable MODIFY (col VARCHAR(100) DEFAULT 'some value');
Using the above approach, col values which are already NULL should remain NULL, at least from the point of view of inserts not changing those NULL values. And newly inserted records which do not specify a value for col should receive the default value some value.
Here's a demonstration which shows what's going on.
First, a test table and some inserts:
SQL> create table test (id number, col varchar2(10));
Table created.
SQL> insert into test (id, col) values (1, null);
1 row created.
SQL> insert into test (id, col) values (2, 'Littlefoot');
1 row created.
SQL> select * from test;
ID COL
---------- ----------
1
2 Littlefoot
Alter the table so that newly added rows contain 'some value' for the COL column:
SQL> alter table test modify col default 'some value';
Table altered.
OK; and now, important part of the story: pay attention to following:
SQL> -- this won't work as you wanted, because I explicitly inserted NULL into COL
SQL> insert into test (id, col) values (3, null);
1 row created.
SQL> -- this will work, because COL is omitted from the INSERT statement
SQL> insert into test (id) values (4);
1 row created.
SQL> select * From test;
ID COL
---------- ----------
1
2 Littlefoot
3
4 some value
SQL>
See? If you explicitly put NULL into a column, it won't get the default value.
However, if you were on 12c (I know, you aren't - just saying, for future reference), there's yet another option: DEFAULT ON NULL. It goes like this:
SQL> alter table test modify col default on null 'some value';
alter table test modify col default on null 'some value'
*
ERROR at line 1:
ORA-02296: cannot enable (SCOTT.) - null values found
Ooops! Won't work if there are NULLs in the column. I know #2 that you don't want to modify existing rows, but - for this demonstration, I'll do that:
SQL> update test set col = 'x' where col is null;
2 rows updated.
SQL> alter table test modify col default on null 'some value';
Table altered.
OK; let's see how it behaves: I'm explicitly inserting NULL into the column. In the previous example, it didn't put 'some value' in there, but left it NULL. How about now?
SQL> insert into test (id, col) values (5, null);
1 row created.
SQL> select * From test;
ID COL
---------- ----------
1 x
2 Littlefoot
3 x
4 some value
5 some value
Nice; we have 'some value' in the column.
Now you have some more info about the issue; see if it helps.
As Littlefoot mentioned, If you explicitly put NULL into a column, it won't get the default value.
If no value is mentioned for the column in the insert query, it uses DEFAULT. But, an explicit NULL overrides the default expression.
For 12c and above you can use the DEFAULT ON NULL option.
For prior versions, only way as far as I can tell is to replicate that functionality through a TRIGGER
CREATE TABLE YOURTABLE ( yourcolumn VARCHAR(100) );
CREATE OR REPLACE TRIGGER trg_mod_yourtabcol BEFORE
INSERT ON yourtable
FOR EACH ROW
WHEN ( new.yourcolumn IS NULL )
BEGIN
:new.yourcolumn := 'SOME DEFAULT VALUE';
END;
/
INSERT INTO YOURTABLE(yourcolumn) VALUES(NULL);
select * from YOURTABLE;
Table YOURTABLE created.
Trigger TRG_MOD_YOURTABCOL compiled
1 row inserted.
YOURCOLUMN
----------------------------------------------------------------------------------------------------
SOME DEFAULT VALUE
1 row selected.

error ora-00922: missing or invalid operation on trigger

I was trying to set up a simple trigger when something is deleted from enrolls it also deletes from scores and student tables. I feel like I have set everything up properly, but I keep getting this error: error ora-00922: missing or invalid operation. I have done some research into the error, but I am not getting anywhere with. I am doing this in sql developer. I am semi new to sql so any help would be greatly appreciated. My code is below:
delimiter //
create or replace TRIGGER enrolls_trigger
AFTER DELETE ON ENROLLS
FOR EACH ROW
BEGIN
DELETE FROM scores
WHERE scores.sid= old.sid
AND scores.term = old.term AND scores.lineno = old.lineno
AND scores.compname = old.compname AND scores.points = old.points;
DELETE FROM students
WHERE students.sid = old.sid;
END//
Your syntax is a bit off. To reference the previous value of a DML transaction, you use :old.
-- delimiter
CREATE OR REPLACE TRIGGER enrolls_trigger AFTER
DELETE ON enrolls
FOR EACH ROW
BEGIN
DELETE FROM scores
WHERE
scores.sid =:old.sid
AND scores.term =:old.term
AND scores.lineno =:old.lineno
AND scores.compname =:old.compname
AND scores.points =:old.points;
DELETE FROM students
WHERE
students.sid =:old.sid;
END;
--delimiter
Also, if you're using SQL Developer, you'll want to have an ';' after your END keyword on the trigger body.
Trigger Docs
For better help going forward, include your TABLE DDL. I created these for ease of use.
CREATE TABLE enrolls (
sid INTEGER,
term INTEGER,
lineno INTEGER,
compname VARCHAR2(10),
points INTEGER
);
CREATE TABLE scores (
sid INTEGER,
term INTEGER,
compname VARCHAR2(10),
points INTEGER,
lineno INTEGER
);
CREATE TABLE students (
sid INTEGER
);
I'd suggest another approach - foreign key constraints created with the ON DELETE CASCADE option. Have a look at the following example.
Thanks to Jeff who provided CREATE TABLE statements which I've slightly modified, i.e. added only necessary constraints. Note that I've chosen only the SID column to be a foreign key from the SCORES table to ENROLLS. BTW, what's the point in repeating that many columns in the SCORES table? I'd suggest you to keep only the foreign key constraint column (such as SID), and omit the others.
Finally, here we go: Create tables:
SQL> CREATE TABLE enrolls (
2 sid INTEGER constraint pk_en primary key,
3 term INTEGER,
4 lineno INTEGER,
5 compname VARCHAR2(10),
6 points INTEGER
7 );
Table created.
SQL> CREATE TABLE scores (
2 sid INTEGER,
3 term INTEGER,
4 lineno INTEGER,
5 compname VARCHAR2(10),
6 points INTEGER,
7 constraint fk_sco_en foreign key (sid)
8 references enrolls
9 on delete cascade
10 );
Table created.
SQL> CREATE TABLE students (
2 sid INTEGER,
3 constraint fk_stu_en foreign key (sid)
4 references enrolls
5 on delete cascade
6 );
Table created.
SQL>
Insert sample data:
SQL> insert into enrolls (sid, term) values (100, 1);
1 row created.
SQL> insert into enrolls (sid, term) values (200, 2);
1 row created.
SQL> insert into scores (sid, term) values (100, 1);
1 row created.
SQL> insert into scores (sid, term) values (200, 2);
1 row created.
SQL> insert into students (sid) values (100);
1 row created.
SQL> insert into students (sid) values (200);
1 row created.
SQL>
SQL> select * From students;
SID
----------
100
200
SQL> select * From scores;
SID TERM LINENO COMPNAME POINTS
---------- ---------- ---------- ---------- ----------
100 1
200 2
SQL> select * From enrolls;
SID TERM LINENO COMPNAME POINTS
---------- ---------- ---------- ---------- ----------
100 1
200 2
SQL>
Now: if I delete a row from the ENROLLS table, Oracle will do the rest:
SQL> delete from enrolls where sid = 100;
1 row deleted.
SQL> select * From students;
SID
----------
200
SQL> select * From scores;
SID TERM LINENO COMPNAME POINTS
---------- ---------- ---------- ---------- ----------
200 2
SQL> select * From enrolls;
SID TERM LINENO COMPNAME POINTS
---------- ---------- ---------- ---------- ----------
200 2
SQL>
See? SID = 100 has been deleted from all tables, without any additional coding (i.e. no triggers needed).

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