How to auto increment the id in oracle? - oracle

Is there any way to auto increment the id in oracle?
UPDATE: It's working but the sequence start in 2 instead of 1. I already set the sequence start with 1
If it possible not use the sequence but still id's will be auto increment?
Here:
CREATE TABLE tblname
(
fieldname_id number(25),
contract_number number(12) not null,
CONSTRAINT letter_status_pk PRIMARY KEY (fieldname_id, contract_number)
);
Sequence w/trigger:
create sequence fieldname_id_sequence start with 1
increment by 1
minvalue 1;
create trigger tr_tblname
before insert on tblname
for each row
begin
select fieldname_id_sequence.nextval into :NEW.fieldname_id from dual;
end;
insert data:
insert all
into tblname(contract_number,fieldname1,fieldname2,fieldname3,fieldname4,fieldname5,fieldname6,fieldname7,fieldname8,fieldname8,fieldname10,fieldname11) values(3300026224,'values','values','values','3/12/2014','values','values','3/18/2014','3/7/2014','values','values')
into tblname(contract_number,fieldname1,fieldname2,fieldname3,fieldname4,fieldname5,fieldname6,fieldname7,fieldname8,fieldname8,fieldname10,fieldname11) values (3300016335,'values','values','values','3/12/2014','values','values','3/18/2014','3/7/2014','values','values')
select 1 from dual;

you can model it easily with a sequence and a trigger:
Create sequence sequence_name start with value increment by value minvalue value maxvalue value;
First, let’s create an emp table with primary key constraint on emp_id column.
SQL> create table emp ( emp_id number(10),
fname varchar2(25),
lname varchar2(25),
constraint pk_emp_id PRIMARY KEY(emp_id)
);
Now let’s create a sequence.
SQL> Create sequence emp_sequence start with 1
increment by 1
minvalue 1
maxvalue 10000;
Now we have created a sequence object named emp_sequence with starting value as 1 and incrementing by 1 from 1 (minvalue) to 10000 (maxvalue)
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.

Oracle 12c introduces IDENTITY COLUMNS.
SQL> CREATE TABLE new_identity_table
2 (
3 ID NUMBER GENERATED ALWAYS AS IDENTITY,
4 text VARCHAR2(50)
5 );
Table created.
SQL>
SQL> INSERT
2 INTO new_identity_table
3 (
4 text
5 )
6 VALUES
7 (
8 'This table has an identity column'
9 );
1 row created.
SQL> column text format A40;
SQL>
SQL> select * from new_identity_table;
ID TEXT
---------- ----------------------------------------
1 This table has an identity column
SQL>
Oracle creates a sequence to populate the identity column. You can find it named as ISEQ$$
SQL> select sequence_name, min_value, max_value, increment_by from user_sequences;
SEQUENCE_NAME MIN_VALUE MAX_VALUE INCREMENT_BY
-------------------- ---------- ---------------------------- ------------
ISEQ$$_93199 1 9999999999999999999999999999 1
SQL>
More more information about the identity columns, use the ALL_TAB_IDENTITY_COLS view.
SQL> SELECT table_name,
2 column_name,
3 generation_type,
4 identity_options
5 FROM all_tab_identity_cols
6 WHERE owner = 'LALIT'
7 ORDER BY 1, 2;
TABLE_NAME COLUMN_NAME GENERATION IDENTITY_OPTIONS
-------------------- --------------- ---------- --------------------------------------------------
NEW_IDENTITY_TABLE ID ALWAYS START WITH: 1, INCREMENT BY: 1, MAX_VALUE: 9999999
999999999999999999999, MIN_VALUE: 1, CYCLE_FLAG: N
, CACHE_SIZE: 20, ORDER_FLAG: N
SQL>

Related

How to automate sql file execution?

We have CICD in place from long time for our application. Now, we are planning to automate DB script execution as well.
PFB the requirement.
For example, we have create_tables.sql and alter_tables.sql files.
create_tables.sql contains:
CREATE TABLE EMPLOYEE_DETAILS (
EMP_ID VARCHAR2(128 CHAR) NOT NULL,
FIRSTNAME VARCHAR2(128 CHAR),
LASTNAME VARCHAR2(128 CHAR),
CONSTRAINT REQUESTSUBMITTERS_PK PRIMARY KEY ( EMP_ID )
);
alter_tables.sql contains:
--v0.1
ALTER TABLE EMPLOYEE_DETAILS MODIFY FIRSTNAME VARCHAR2(256);
COMMIT;
--v0.2
ALTER TABLE EMPLOYEE_DETAILS MODIFY FIRSTNAME VARCHAR2(256) NOT NULL;
ALTER TABLE EMPLOYEE_DETAILS MODIFY LASTNAME VARCHAR2(256) NOT NULL;
COMMIT;
--v0.3
ALTER TABLE EMPLOYEE_DETAILS ADD EMAIL VARCHAR2(256) NOT NULL;
COMMIT;
Assume that we have an environments ABC. This environment has all changes available in create_tables.sql file but only --v0.1 change from alter_tables.sql file.
Now, we just want to promote JUST --v0.2 change from alter_tables.sql file to this environment. Please note that we don't want to promote changes --v0.1 and --v0.3 from alter_tables.sql file.
So, in general there will be --v0.xxx (a unique incremental indicator) in each sql file to specify which sql statements to execute.
Can you please let me know what could be the way to automate with this approach.
Also, please feel free to suggest any other solution which you think is better than above one.
First of all, ALTER is a DDL and it implicitly commits before and after executing that command, so - explicitly COMMITting is pretty much useless.
From my point of view, your approach is too difficult to apply as you have all the changes stored in the same file so you'd have to parse it and extract only some - desired - parts of it to be executed.
How about creating a set of tables that contains what to apply? Here's an example:
SQL> create table t_change_master
2 (change number constraint pk_cha primary key,
3 change_date date,
4 cb_apply number(1) default 0 not null,
5 applied_date date
6 );
Table created.
SQL> create table t_change_detail
2 (id number constraint pk_chadet primary key,
3 change number constraint fk_chadet_cha references t_change_master (change),
4 command varchar2(200),
5 cb_ok number(1),
6 error varchar2(200)
7 );
Table created.
Some sample data:
SQL> insert into t_change_master (change, change_date, cb_apply)
2 select 1, date '2022-06-25', 1 from dual union all
3 select 2, date '2022-06-26', 0 from dual union all
4 select 3, date '2022-06-28', 0 from dual;
3 rows created.
Note that ID = 1 and 4 contain duplicate commands:
SQL> insert into t_change_detail (id, change, command)
2 select 1, 1, 'alter table test add firstname varchar2(20)' from dual union all
3 select 2, 1, 'alter table test modify firstname varchar2(15)' from dual union all
4 select 3, 2, 'alter table test add lastname varchar2(20)' from dual union all
5 select 4, 2, 'alter table test add firstname varchar2(30)' from dual union all
6 select 5, 3, 'alter table test add address varchar2(30)' from dual;
5 rows created.
SQL>
This is table that will be used in this playground:
SQL> create table test (id number);
Table created.
Procedure that does the job; in two nested loops, it reads rows from the master table which are scheduled to run (cb_apply = 1) but have not been ran yet (applied_date is null). Inner loop just reads what to do, executes it and logs whether it was successful or not.
Basically, you'd schedule its execution using DBMS_SCHEDULER (or DBMS_JOB, depending on your database version):
SQL> create or replace procedure p_change is
2 l_err varchar2(200);
3 begin
4 for cur_m in (select change
5 from t_change_master
6 where cb_apply = 1
7 and applied_date is null
8 )
9 loop
10 for cur_d in (select id, command
11 from t_change_detail
12 where change = cur_m.change
13 )
14 loop
15 begin
16 dbms_output.put_line(cur_d.command);
17 execute immediate cur_d.command;
18
19 update t_change_detail set
20 cb_ok = 1
21 where id = cur_d.id;
22 exception
23 when others then
24 l_err := sqlerrm;
25 update t_change_detail set
26 cb_ok = 0,
27 error = l_err
28 where id = cur_d.id;
29 end;
30 end loop;
31 update t_change_master set
32 applied_date = sysdate
33 where change = cur_m.change;
34 end loop;
35 end;
36 /
Procedure created.
SQL>
OK, let's try it. Setting date format, just to know what is what:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> set serveroutput on;
SQL> begin
2 p_change;
3 end;
4 /
alter table test add firstname varchar2(20)
alter table test modify firstname varchar2(15)
PL/SQL procedure successfully completed.
SQL> select * from t_change_master;
CHANGE CHANGE_DATE CB_APPLY APPLIED_DATE
------- ------------------- ---------- -------------------
1 25.06.2022 00:00:00 1 05.07.2022 17:50:01
2 26.06.2022 00:00:00 0
3 28.06.2022 00:00:00 0
SQL> select * from t_change_detail;
ID CHANGE COMMAND CB_OK ERROR
--- ------- ---------------------------------------------- ------ ----------------------------------------
1 1 alter table test add firstname varchar2(20) 1
2 1 alter table test modify firstname varchar2(15) 1
3 2 alter table test add lastname varchar2(20)
4 2 alter table test add firstname varchar2(30)
5 3 alter table test add address varchar2(30)
SQL>
Let's now run change = 2:
SQL> update t_change_master set cb_apply = 1 where change = 2;
1 row updated.
SQL> begin
2 p_change;
3 end;
4 /
alter table test add lastname varchar2(20)
alter table test add firstname varchar2(30)
PL/SQL procedure successfully completed.
SQL> select * from t_change_master;
CHANGE CHANGE_DATE CB_APPLY APPLIED_DATE
------- ------------------- ---------- -------------------
1 25.06.2022 00:00:00 1 05.07.2022 17:50:01
2 26.06.2022 00:00:00 1 05.07.2022 17:50:58
3 28.06.2022 00:00:00 0
SQL> select * from t_change_detail;
ID CHANGE COMMAND CB_OK ERROR
--- ------- ---------------------------------------------- ------ ----------------------------------------
1 1 alter table test add firstname varchar2(20) 1
2 1 alter table test modify firstname varchar2(15) 1
3 2 alter table test add lastname varchar2(20) 1
4 2 alter table test add firstname varchar2(30) 0 ORA-01430: column being added already
exists in table
5 3 alter table test add address varchar2(30)
SQL>
Right; it kind of works.
Certainly, that piece of code (I wrote in a matter of minutes) could/should be improved, but that's just the general idea.
On the other hand, why wouldn't you do that using version control system, such as Git or Subversion? Good people developed these tools which are much, much more powerful that anything me (or you) could "invent" in such a short time. I guess it's worth to check these products.

PL/SQL: How to insert all records from table type to another table without for loop

I have probably trivial problem but I can't nail the logic quite right.
I have following types:
create or replace TYPE test_rec FORCE
AS OBJECT (ref_id NUMBER (20)
,ref_type VARCHAR2 (4));
create or replace TYPE test_ref_tbl FORCE
AS TABLE OF test_rec;
and actual table
CREATE TABLE my_tbl
( id number(10) NOT NULL,
ref_id varchar2(20) NOT NULL,
ref_type varchar2(4),
CONSTRAINT my_pk PRIMARY KEY (id)
);
Now, in one procedure I get variable test_ref_tbl with data and I have to insert everything to my_tbl, also id should be generated from sequence.
I managed to do this quite easily with for loop
FOR i IN 1 .. test_ref_tbl.COUNT LOOP
INSERT INTO my_tbl(id
,ref_id
,ref_type)
VALUES (my_test_sequence.NEXTVAL
,test_ref_tbl(i).ref_id
,test_ref_tbl(i).ref_type
);
END LOOP;
and everything works fine, but I got alot of flack for inserting data in for loop, I'm not plsql developer so maybe my colleagues are making my job harder just for the hell of it.
But to get back on topic, is there a way to do this without for loop?
Thanks
Yes, there is. Here's an example:
Creating test case first:
SQL> CREATE OR REPLACE TYPE test_rec FORCE AS OBJECT
2 (
3 ref_id NUMBER (20),
4 ref_type VARCHAR2 (4)
5 );
6 /
Type created.
SQL> CREATE OR REPLACE TYPE test_ref_tbl FORCE AS TABLE OF test_rec;
2 /
Type created.
SQL> CREATE TABLE my_tbl
2 (
3 id NUMBER (10) NOT NULL,
4 ref_id VARCHAR2 (20) NOT NULL,
5 ref_type VARCHAR2 (4),
6 CONSTRAINT my_pk PRIMARY KEY (id)
7 );
Table created.
SQL> CREATE SEQUENCE my_test_sequence;
Sequence created.
As data source, I'm using Scott's DEPT table.
SQL> DECLARE
2 l_tab test_ref_tbl;
3 BEGIN
4 SELECT test_rec (deptno, SUBSTR (dname, 1, 4))
5 BULK COLLECT INTO l_tab
6 FROM dept;
7
8 -- this is what you're looking for
9 INSERT INTO my_tbl (id, ref_id, ref_type)
10 SELECT my_test_sequence.NEXTVAL, t.*
11 FROM TABLE (l_tab) t;
12 END;
13 /
PL/SQL procedure successfully completed.
SQL> SELECT * FROM my_tbl;
ID REF_ID REF_
---------- -------------------- ----
1 10 ACCO
2 20 RESE
3 30 SALE
4 40 OPER
SQL>

Create Trigger in Oracle, in order to check two Dates

I would like to create a Trigger in Oracle, in order to check the Current Date with the Date that is stored in a specific column and if they are equal, I would like to change a boolean value on the same table. I am new to Oracle and especially on creating triggers. Any help is much appreciated.
CREATE TABLE DISCIPLINARYAUDIT
(
DISCIPLINARYAUDITID NUMBER(19, 0) NOT NULL
, DISCIPLINARYAUDITTYPE VARCHAR2(255 CHAR) NOT NULL
, REVOCATIONORCOMPLETION NUMBER(1, 0)
, STARTDATE DATE
, ENDDATE DATE
)
When endDate equals with current Date, RevocationORCompletion must chenage from 0 to 1.
Thank you in advance.
Here's an example.
Date format and today's date:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
Sample table:
SQL> create table test (id number, specific_column date, boolean_column varchar2(10));
Table created.
SQL> insert into test values (1, trunc(sysdate), 'FALSE');
1 row created.
SQL> insert into test values (2, trunc(sysdate) - 2, 'FALSE');
1 row created.
SQL> select * from test order by id;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
1 04.06.2020 FALSE
2 02.06.2020 FALSE
Trigger:
SQL> create or replace trigger trg_biu_test
2 before insert or update on test
3 for each row
4 begin
5 if :new.specific_column = trunc(sysdate) then
6 :new.boolean_column := 'TRUE';
7 end if;
8 end;
9 /
Trigger created.
Testing:
SQL> update test set id = 3 where id = 1;
1 row updated.
SQL> update test set id = 5 where id = 2;
1 row updated.
SQL> select * from test;
ID SPECIFIC_C BOOLEAN_CO
---------- ---------- ----------
3 04.06.2020 TRUE
5 02.06.2020 FALSE
SQL>

How to add extra column in the INTO section of SQL Trigger

How to add an extra column (say column_2) in the below INTO section of my code along with my Column_1. I assume we can do that by adding comma (,) and just add column_2 (like this INTO :new.Column_1, new.column_2). I'm missing something?
create or replace trigger trigger_name
BEFORE INSERT
ON table_name
FOR EACH ROW
BEGIN
SELECT SEQUENCE_NUMBER.NEXTVAL
INTO :new.Column_1
FROM dual;
END;
It is easy to confirm whether you are right (or wrong). I hope you got the answer during the past 6 hours. If not, here's an example:
SQL> create table test
2 (id number,
3 datum date);
Table created.
SQL> create sequence seq_test;
Sequence created.
SQL> create or replace trigger trg_bi_test
2 before insert on test
3 for each row
4 begin
5 select seq_test.nextval, sysdate
6 into :new.id, :new.datum
7 from dual;
8 end;
9 /
Trigger created.
SQL> insert into test (id) values (-1);
1 row created.
SQL> select * From test;
ID DATUM
---------- -------------------
1 21.06.2019 21:54:08
SQL>

Oracle 11g: Can I create a number column that stores only 1 byte?

I need a number column to serve as an indicator for something I am working on, but I don't want it to take up more than a single byte per record. If I use NUMBER(1), would this satisfy my requirement?
A NUMBER(1) column will take up however much space it requires to store a 1 digit number. That is likely to be more than 1 byte (negative numbers will require 3 bytes, a 0 requires 1 byte, the numbers 1-9 require 2 bytes)
SQL> create table foo( col1 number(1) );
Table created.
SQL> insert into foo values( 1 );
1 row created.
SQL> insert into foo values( 9 );
1 row created.
SQL> insert into foo values( -7 );
1 row created.
SQL> select vsize(col1), col1 from foo;
VSIZE(COL1) COL1
----------- ----------
2 1
2 9
3 -7
A table with a VARCHAR2(1 BYTE) column, on the other hand, will use at most 1 byte per row of storage
SQL> create table bar( col1 varchar2(1) );
Table created.
SQL> insert into bar values( 'Y' );
1 row created.
SQL> insert into bar values( 'N' );
1 row created.
SQL> select vsize(col1), col1 from bar;
VSIZE(COL1) C
----------- -
1 Y
1 N

Resources