Auto Increment for Oracle - 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>

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.

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>

How to create a unique id for an existing table in PL SQL?

The situation is that, when I import a file into the database, one of the first thing I usually do is to assign an unique ID for each record.
I normally do below in TSQL
ALTER TABLE MyTable
ADD ID INT IDENTITY(1,1)
I am wondering if there is something similar in PL SQL?
All my search result come back with multiple steps.
Then I'd like to know what PL SQL programmer typically do to ID records after importing a file. Do they do that?
The main purpose for me to ID these records is to trace it back after manipulation/copying.
Again, I understand there is solution there, my further question is whether PL SQL programmer actually do that, or there is other alternative which making this step not necessary in PL SQL?
OK then, as you're on Oracle 11g, there's no identity column there so - back to multiple steps. Here's an example:
I'm creating a table that simulates your imported table:
SQL> create table tab_import as
2 select ename, job, sal
3 from emp
4 where deptno = 10;
Table created.
Add the ID column:
SQL> alter table tab_import add id number;
Table altered.
Create a sequence which will be used to populate the ID column:
SQL> create sequence seq_imp;
Sequence created.
Update current rows:
SQL> update tab_import set
2 id = seq_imp.nextval;
3 rows updated.
Create a trigger which will take care about future inserts (if any):
SQL> create or replace trigger trg_bi_imp
2 before insert on tab_import
3 for each row
4 begin
5 :new.id := seq_imp.nextval;
6 end;
7 /
Trigger created.
Check what's in the table at the moment:
SQL> select * from tab_import;
ENAME JOB SAL ID
---------- --------- ---------- ----------
CLARK MANAGER 2450 1
KING PRESIDENT 5000 2
MILLER CLERK 1300 3
Let's import some more rows:
SQL> insert into tab_import (ename, job, sal)
2 select ename, job, sal
3 from emp
4 where deptno = 20;
3 rows created.
The trigger had silently populated the ID column:
SQL> select * From tab_import;
ENAME JOB SAL ID
---------- --------- ---------- ----------
CLARK MANAGER 2450 1
KING PRESIDENT 5000 2
MILLER CLERK 1300 3
SMITH CLERK 800 4
JONES MANAGER 2975 5
FORD ANALYST 3000 6
6 rows selected.
SQL>
Shortly: you need to
alter table and add the ID column
create a sequence
create a trigger
The end.
The answer given by #Littlefoot would be my recommendation too - but still I thought I could mention the following variant which will work only if you do not intend to add more rows to the table later.
ALTER TABLE MyTable add id number(38,0);
update MyTable set id = rownum;
commit;
My test:
SQL> create table tst as select * from all_tables;
Table created.
SQL> alter table tst add id number(38,0);
Table altered.
SQL> update tst set id = rownum;
3815 rows updated.
SQL> alter table tst add constraint tstPk primary key (id);
Table altered.
SQL>
SQL> select id from tst where id < 15;
ID
----------
1
2
3
4
5
6
7
8
9
10
11
ID
----------
12
13
14
14 rows selected.
But as mentioned initially,- this only fixes numbering for the rows you have at the time of the update - your'e not going to get new id values for new rows anytime later - if you need that, go for the sequence solution.
You can add an id column to a table with a single statement (Oracle 11g, see dbfiddle):
alter table test_
add id raw( 16 ) default sys_guid() ;
Example:
-- create a table without an id column
create table test_ ( str )
as
select dbms_random.string( 'x', 16 )
from dual
connect by level <= 10 ;
select * from test_ ;
STR
ULWL9EXFG6CIO72Z
QOM0W1R9IJ2ZD3DW
YQWAP4HZNQ57C2UH
EETF2AXD4ZKNIBBF
W9SECJYDER793MQW
alter table test_
add id raw( 16 ) default sys_guid() ;
select * from test_ ;
STR ID
ULWL9EXFG6CIO72Z 0x782C6EBCAE2D7B9FE050A00A02005D65
QOM0W1R9IJ2ZD3DW 0x782C6EBCAE2E7B9FE050A00A02005D65
YQWAP4HZNQ57C2UH 0x782C6EBCAE2F7B9FE050A00A02005D65
EETF2AXD4ZKNIBBF 0x782C6EBCAE307B9FE050A00A02005D65
W9SECJYDER793MQW 0x782C6EBCAE317B9FE050A00A02005D65
Testing
-- Are the id values unique and not null? Yes.
alter table test_
add constraint pkey_test_ primary key ( id ) ;
-- When we insert more rows, will the id be generated? Yes.
begin
for i in 1 .. 100
loop
insert into test_ (str) values ( 'str' || to_char( i ) ) ;
end loop ;
end ;
/
select * from test_ order by id desc ;
-- last 10 rows of the result
STR ID
str100 0x782C806E16A5E998E050A00A02005D81
str99 0x782C806E16A4E998E050A00A02005D81
str98 0x782C806E16A3E998E050A00A02005D81
str97 0x782C806E16A2E998E050A00A02005D81
str96 0x782C806E16A1E998E050A00A02005D81
str95 0x782C806E16A0E998E050A00A02005D81
str94 0x782C806E169FE998E050A00A02005D81
str93 0x782C806E169EE998E050A00A02005D81
str92 0x782C806E169DE998E050A00A02005D81
str91 0x782C806E169CE998E050A00A02005D81
Regarding your other questions:
{1} Then I'd like to know what PL SQL programmer typically do to ID records after importing a file. Do they do that? The main purpose for me to ID these records is to trace it back after manipulation/copying.
-> As you know, the purpose of an id is: to identify a row. We don't "do anything to IDs". Thus, your usage of IDs seems legit.
{2} Again, I understand there is solution there, my further question is whether PL SQL programmer actually do that, or there is other alternative which making this step not necessary in PL SQL?
-> Not quite sure what you are asking here. Although there is a ROWID() pseudocolumn (see documentation), we should not use it to identify rows.
"You should not use ROWID as the primary key of a table. If you delete
and reinsert a row with the Import and Export utilities, for example,
then its rowid may change. If you delete a row, then Oracle may
reassign its rowid to a new row inserted later."

Getting data from different tables between dates when each table has it on date modified

Like to get some views from you all, regarding one scenario i'm struggling with currently. Below is a problem statement
I have Table A , B , C
A has below column
user|modified date| wokred_on A | ..some more related to user operation
B has columns
user | modified date | worked on B | ..some other columns
C has columsn
user | modified date | worked on C| ..some other columns
these tables are not have any direct relation except then user.
we have to pull data from these tables for a user between given dates with the count op action or work he has done between a given date range?
my struggle here is these each table has it's own date modified if a date range selected which is not in other column but still i need to pull the data as user has worked on it in between dates.
can it be possible to select these dates and have the in one column so that one can put that in where clause and having outer joins to pull other records ?
Sorry for this big problem statement. any suggestions are very much appreciated
Below is a use case.just extending the assumption given by littlefoot
First, test case:
SQL> create table a (cuser varchar2(10), modified_date date,action );
varchar2 (10) )
Table created.
SQL> create table b (
Table created.cuser varchar2(10), modified_date date,action
varchar2 (10) );
SQL> create table c (cuser varchar2(10), modified_date date,action
varchar2 (10) ));
Table created.
SQL> insert into a values ('lf', date '2018-05-01', 'issue raised');
1 row created.
SQL> insert into a values ('mc', date '2018-05-01', 'issue raised ');
1 row created.
SQL> insert into b values ('lf', date '2018-05-01',issue raised');
1 row created.
SQL> insert into b values ('lf', date '2018-05-01','issue resolved');
1 row created.
SQL> insert into c values ('if', date '2018-05-28',' issue resolved');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13','issue raised');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13','issue resolved');
1 row created.
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from a;
CUSER MODIFIED_D. ACTION
---------- ----------
lf 2018-05-01 issue raised
mc 2018-05-01 issue raised
SQL> select * from b;
CUSER MODIFIED_D ACTION
---------- ----------. ______________
lf 2018-05-01 issue raised
lf 2018-05-01. issue resolve
SQL> select * from c;
CUSER MODIFIED_D. ACTION
---------- ----------
If 2018-05-28. issue resolve
mc 2018-05-13. issue raised
mc 2018-05-13. issue resolve
CUSER DATE CNT_ISSUE_RAISED CNT_ISSUE_RESOLVED
------ ------- --------------- -------------------
if 2018-05-01 2 1
lf 2018-05-28 0 1
mc 2018-05-01 0 1
mc 2018-05-13 1 1
This is how I understood the question.
First, test case:
SQL> create table a (cuser varchar2(10), modified_date date);
Table created.
SQL> create table b (cuser varchar2(10), modified_date date);
Table created.
SQL> create table c (cuser varchar2(10), modified_date date);
Table created.
SQL> insert into a values ('lf', date '2018-05-01');
1 row created.
SQL> insert into a values ('mc', date '2018-05-15');
1 row created.
SQL> insert into b values ('lf', date '2018-05-07');
1 row created.
SQL> insert into b values ('lf', date '2018-05-08');
1 row created.
SQL> insert into c values ('jw', date '2018-05-28');
1 row created.
SQL> insert into c values ('mc', date '2018-05-13');
1 row created.
SQL> insert into c values ('mc', date '2018-05-22');
1 row created.
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from a;
CUSER MODIFIED_D
---------- ----------
lf 2018-05-01
mc 2018-05-15
SQL> select * from b;
CUSER MODIFIED_D
---------- ----------
lf 2018-05-07
lf 2018-05-08
SQL> select * from c;
CUSER MODIFIED_D
---------- ----------
jw 2018-05-28
mc 2018-05-13
mc 2018-05-22
Query which returns desired result - number of rows per each user in every table, in desired date period. As I use SQL*Plus, variables are preceded by && to avoid multiple insert requests. In a tool you use, that might be a colon (:).
SQL> select nvl(nvl(a.cuser, b.cuser), c.cuser) cuser,
2 count(distinct a.modified_date) cnt_a,
3 count(distinct b.modified_date) cnt_b,
4 count(distinct c.modified_date) cnt_c
5 from a full outer join b on a.cuser = b.cuser
6 full outer join c on a.cuser = c.cuser
7 where a.modified_date between &&date_from and &&date_to
8 or b.modified_date between &&date_from and &&date_to
9 or c.modified_date between &&date_from and &&date_to
10 group by nvl(nvl(a.cuser, b.cuser), c.cuser)
11 order by 1;
Enter value for date_from: '2018-05-01'
Enter value for date_to: '2018-06-01'
CUSER CNT_A CNT_B CNT_C
---------- ---------- ---------- ----------
jw 0 0 1
lf 1 2 0
mc 1 0 2
SQL>

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).

Resources