how to use one procedure to insert into two table - oracle

I want to insert value into EVENT table and EventCost table by using only one procedure.
The PK of event is EventID and it is the FK of EventCost table.
I tried to use SCOPE_IDENTITY() for EventID but still fail to create the procedure.
2)Do I need to declare the v_EventID in the header for two times? (One for the Event table , one for the eventCost table)
CREATE OR REPLACE PROCEDURE PRC_ADD_OVER_BUDGET_EVENT
( V_eventID IN VARCHAR
,V_EventType IN VARCHAR
,V_EventBudget IN NUMBER
,V_organizerID IN VARCHAR
,v_CostID IN VARCHAR
,v_FoodBeverage IN NUMBER
,v_wine IN NUMBER
,v_Decoration IN NUMBER
,v_rentalfee IN NUMBER
,v_facility IN NUMBER
,v_EventID IN VARCHAR)
AS
BEGIN
INSERT INTO Event
values
(next_eventid_seq,null,v_eventbudget,null,null,null,v_organizerID)
INSERT INTO EventCost
values
(next_Costid_seq,v_FoodBeverage,v_Wine,v_Decoration,v_RentalFee,v_Facility,SCOPE_IDENTITY())
End;
/

Use returning into clause:
CREATE OR REPLACE PROCEDURE PRC_ADD_OVER_BUDGET_EVENT
( V_eventID IN VARCHAR
,V_EventType IN VARCHAR
,V_EventBudget IN NUMBER
,V_organizerID IN VARCHAR
,v_CostID IN VARCHAR
,v_FoodBeverage IN NUMBER
,v_wine IN NUMBER
,v_Decoration IN NUMBER
,v_rentalfee IN NUMBER
,v_facility IN NUMBER
,v_EventID IN VARCHAR)
AS
event_ID varchar2(64);
BEGIN
INSERT INTO Event
values
(next_eventid_seq,null,v_eventbudget,null,null,null,v_organizerID) returning eventID into event_ID;
INSERT INTO EventCost
values
(next_Costid_seq,v_FoodBeverage,v_Wine,v_Decoration,v_RentalFee,v_Facility,event_ID);
End;
/
P.S. Also a few notes:
Use varchar2 datatype instead of varchar.
When inserting, provide the names of the columns you insert into: insert into Event (col1, col2, col3, ...). In case your table structure is changed, the insert statements will still work.

Related

How to conitnue a consecutive row number in pyspark(AWS glue) [duplicate]

It appears that there is no concept of AUTO_INCREMENT in Oracle, up until and including version 11g.
How can I create a column that behaves like auto increment in Oracle 11g?
There is no such thing as "auto_increment" or "identity" columns in Oracle as of Oracle 11g. However, you can model it easily with a sequence and a trigger:
Table definition:
CREATE TABLE departments (
ID NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
CREATE SEQUENCE dept_seq START WITH 1;
Trigger definition:
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON departments
FOR EACH ROW
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
/
UPDATE:
IDENTITY column is now available on Oracle 12c:
create table t1 (
c1 NUMBER GENERATED by default on null as IDENTITY,
c2 VARCHAR2(10)
);
or specify starting and increment values, also preventing any insert into the identity column (GENERATED ALWAYS) (again, Oracle 12c+ only)
create table t1 (
c1 NUMBER GENERATED ALWAYS as IDENTITY(START with 1 INCREMENT by 1),
c2 VARCHAR2(10)
);
Alternatively, Oracle 12 also allows to use a sequence as a default value:
CREATE SEQUENCE dept_seq START WITH 1;
CREATE TABLE departments (
ID NUMBER(10) DEFAULT dept_seq.nextval NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
SYS_GUID returns a GUID-- a globally unique ID. A SYS_GUID is a RAW(16). It does not generate an incrementing numeric value.
If you want to create an incrementing numeric key, you'll want to create a sequence.
CREATE SEQUENCE name_of_sequence
START WITH 1
INCREMENT BY 1
CACHE 100;
You would then either use that sequence in your INSERT statement
INSERT INTO name_of_table( primary_key_column, <<other columns>> )
VALUES( name_of_sequence.nextval, <<other values>> );
Or you can define a trigger that automatically populates the primary key value using the sequence
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
SELECT name_of_sequence.nextval
INTO :new.primary_key_column
FROM dual;
END;
If you are using Oracle 11.1 or later, you can simplify the trigger a bit
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:new.primary_key_column := name_of_sequence.nextval;
END;
If you really want to use SYS_GUID
CREATE TABLE table_name (
primary_key_column raw(16) default sys_guid() primary key,
<<other columns>>
)
In Oracle 12c onward you could do something like,
CREATE TABLE MAPS
(
MAP_ID INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL,
MAP_NAME VARCHAR(24) NOT NULL,
UNIQUE (MAP_ID, MAP_NAME)
);
And in Oracle (Pre 12c).
-- create table
CREATE TABLE MAPS
(
MAP_ID INTEGER NOT NULL ,
MAP_NAME VARCHAR(24) NOT NULL,
UNIQUE (MAP_ID, MAP_NAME)
);
-- create sequence
CREATE SEQUENCE MAPS_SEQ;
-- create tigger using the sequence
CREATE OR REPLACE TRIGGER MAPS_TRG
BEFORE INSERT ON MAPS
FOR EACH ROW
WHEN (new.MAP_ID IS NULL)
BEGIN
SELECT MAPS_SEQ.NEXTVAL
INTO :new.MAP_ID
FROM dual;
END;
/
Here are three flavors:
numeric. Simple increasing numeric value, e.g. 1,2,3,....
GUID. globally univeral identifier, as a RAW datatype.
GUID (string). Same as above, but as a string which might be easier to handle in some languages.
x is the identity column. Substitute FOO with your table name in each of the examples.
-- numerical identity, e.g. 1,2,3...
create table FOO (
x number primary key
);
create sequence FOO_seq;
create or replace trigger FOO_trg
before insert on FOO
for each row
begin
select FOO_seq.nextval into :new.x from dual;
end;
/
-- GUID identity, e.g. 7CFF0C304187716EE040488AA1F9749A
-- use the commented out lines if you prefer RAW over VARCHAR2.
create table FOO (
x varchar(32) primary key -- string version
-- x raw(32) primary key -- raw version
);
create or replace trigger FOO_trg
before insert on FOO
for each row
begin
select cast(sys_guid() as varchar2(32)) into :new.x from dual; -- string version
-- select sys_guid() into :new.x from dual; -- raw version
end;
/
update:
Oracle 12c introduces these two variants that don't depend on triggers:
create table mytable(id number default mysequence.nextval);
create table mytable(id number generated as identity);
The first one uses a sequence in the traditional way; the second manages the value internally.
Oracle Database 12c introduced Identity, an auto-incremental (system-generated) column.
In the previous database versions (until 11g), you usually implement an Identity by creating a Sequence and a Trigger.
From 12c onward, you can create your own Table and define the column that has to be generated as an Identity.
Assuming you mean a column like the SQL Server identity column?
In Oracle, you use a SEQUENCE to achieve the same functionality. I'll see if I can find a good link and post it here.
Update: looks like you found it yourself. Here is the link anyway:
http://www.techonthenet.com/oracle/sequences.php
Trigger and Sequence can be used when you want serialized number that anyone can easily read/remember/understand. But if you don't want to manage ID Column (like emp_id) by this way, and value of this column is not much considerable, you can use SYS_GUID() at Table Creation to get Auto Increment like this.
CREATE TABLE <table_name>
(emp_id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(30));
Now your emp_id column will accept "globally unique identifier value".
you can insert value in table by ignoring emp_id column like this.
INSERT INTO <table_name> (name) VALUES ('name value');
So, it will insert unique value to your emp_id Column.
Starting with Oracle 12c there is support for Identity columns in one of two ways:
Sequence + Table - In this solution you still create a sequence as you normally would, then you use the following DDL:
CREATE TABLE MyTable
(ID NUMBER DEFAULT MyTable_Seq.NEXTVAL,
...)
Table Only - In this solution no sequence is explicitly specified. You would use the following DDL:
CREATE TABLE MyTable (ID NUMBER GENERATED AS IDENTITY, ...)
If you use the first way it is backward compatible with the existing way of doing things. The second is a little more straightforward and is more inline with the rest of the RDMS systems out there.
it is called Identity Columns and it is available only from oracle Oracle 12c
CREATE TABLE identity_test_tab
(
id NUMBER GENERATED ALWAYS AS IDENTITY,
description VARCHAR2 (30)
);
example of insert into Identity Columns as below
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION');
1 row created.
you can NOT do insert like below
INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION');
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION');
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
useful link
Here is complete solution w.r.t exception/error handling for auto increment, this solution is backward compatible and will work on 11g & 12c, specifically if application is in production.
Please replace 'TABLE_NAME' with your appropriate table name
--checking if table already exisits
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME';
EXCEPTION WHEN OTHERS THEN NULL;
END;
/
--creating table
CREATE TABLE TABLE_NAME (
ID NUMBER(10) PRIMARY KEY NOT NULL,
.
.
.
);
--checking if sequence already exists
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE TABLE_NAME_SEQ';
EXCEPTION WHEN OTHERS THEN NULL;
END;
--creating sequence
/
CREATE SEQUENCE TABLE_NAME_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE NOCYCLE CACHE 2;
--granting rights as per required user group
/
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE_NAME TO USER_GROUP;
-- creating trigger
/
CREATE OR REPLACE TRIGGER TABLE_NAME_TS BEFORE INSERT OR UPDATE ON TABLE_NAME FOR EACH ROW
BEGIN
-- auto increment column
SELECT TABLE_NAME_SEQ.NextVal INTO :New.ID FROM dual;
-- You can also put some other required default data as per need of your columns, for example
SELECT SYS_CONTEXT('USERENV', 'SESSIONID') INTO :New.SessionID FROM dual;
SELECT SYS_CONTEXT('USERENV','SERVER_HOST') INTO :New.HostName FROM dual;
SELECT SYS_CONTEXT('USERENV','OS_USER') INTO :New.LoginID FROM dual;
.
.
.
END;
/
Query to create auto increment in oracle. In below query incrmnt column value will be auto incremented wheneever a new row is inserted
CREATE TABLE table1(
id RAW(16) NOT NULL ENABLE,
incrmnt NUMBER(10,0) GENERATED ALWAYS AS IDENTITY
MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOORDER NOCYCLE NOT NULL ENABLE,
CONSTRAINT PK_table1 PRIMARY KEY (id) ENABLE);
This is how I did this on an existing table and column (named id):
UPDATE table SET id=ROWNUM;
DECLARE
maxval NUMBER;
BEGIN
SELECT MAX(id) INTO maxval FROM table;
EXECUTE IMMEDIATE 'DROP SEQUENCE table_seq';
EXECUTE IMMEDIATE 'CREATE SEQUENCE table_seq START WITH '|| TO_CHAR(TO_NUMBER(maxval)+1) ||' INCREMENT BY 1 NOMAXVALUE';
END;
CREATE TRIGGER table_trigger
BEFORE INSERT ON table
FOR EACH ROW
BEGIN
:new.id := table_seq.NEXTVAL;
END;
FUNCTION GETUNIQUEID_2 RETURN VARCHAR2
AS
v_curr_id NUMBER;
v_inc NUMBER;
v_next_val NUMBER;
pragma autonomous_transaction;
begin
CREATE SEQUENCE sequnce
START WITH YYMMDD0000000001
INCREMENT BY 1
NOCACHE
select sequence.nextval into v_curr_id from dual;
if(substr(v_curr_id,0,6)= to_char(sysdate,'yymmdd')) then
v_next_val := to_number(to_char(SYSDATE+1, 'yymmdd') || '0000000000');
v_inc := v_next_val - v_curr_id;
execute immediate ' alter sequence sequence increment by ' || v_inc ;
select sequence.nextval into v_curr_id from dual;
execute immediate ' alter sequence sequence increment by 1';
else
dbms_output.put_line('exception : file not found');
end if;
RETURN 'ID'||v_curr_id;
END;
FUNCTION UNIQUE2(
seq IN NUMBER
) RETURN VARCHAR2
AS
i NUMBER := seq;
s VARCHAR2(9);
r NUMBER(2,0);
BEGIN
WHILE i > 0 LOOP
r := MOD( i, 36 );
i := ( i - r ) / 36;
IF ( r < 10 ) THEN
s := TO_CHAR(r) || s;
ELSE
s := CHR( 55 + r ) || s;
END IF;
END LOOP;
RETURN 'ID'||LPAD( s, 14, '0' );
END;
Creating a Sequence:
CREATE SEQUENCE SEQ_CM_LC_FINAL_STATUS
MINVALUE 1 MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE;
Adding a Trigger
CREATE OR REPLACE TRIGGER CM_LC_FINAL_STATUS_TRIGGER
BEFORE INSERT
ON CM_LC_FINAL_STATUS
FOR EACH ROW
BEGIN
:NEW.LC_FINAL_STATUS_NO := SEQ_CM_LC_FINAL_STATUS.NEXTVAL;
END;
The first step is to create a SEQUENCE in your database, which is a data object that multiple users can access to automatically generate incremented values. As discussed in the documentation, a sequence in Oracle prevents duplicate values from being created simultaneously because multiple users are effectively forced to “take turns” before each sequential item is generated. –
Finally, we’ll create our SEQUENCE that will be utilized later to actually generate the unique, auto incremented value. –
While we have our table created and ready to go, our sequence is thus far just sitting there but never being put to use. This is where TRIGGERS come in. Similar to an event in modern programming languages, a TRIGGER in Oracle is a stored procedure that is executed when a particular event occurs. Typically a TRIGGER will be configured to fire when a table is updated or a record is deleted, providing a bit of cleanup when necessary. –
In our case, we want to execute our TRIGGER prior to INSERT into our CM_LC_FINAL_STATUS table, ensuring our SEQUENCE is incremented and that new value is passed onto our primary key column.
create trigger t1_trigger
before insert on AUDITLOGS
for each row
begin
select t1_seq.nextval into :new.id from dual;
end;
only I have to just change the table name (AUDITLOGS) with your table name and new.id with new.column_name
oracle has sequences AND identity columns in 12c
http://www.oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1.php#identity-columns
I found this but not sure what rdb 7 is
http://www.oracle.com/technetwork/products/rdb/0307-identity-columns-128126.pdf
Maybe just try this simple script:
http://www.hlavaj.sk/ai.php
Result is:
CREATE SEQUENCE TABLE_PK_SEQ;
CREATE OR REPLACE TRIGGER TR_SEQ_TABLE BEFORE INSERT ON TABLE FOR EACH ROW
BEGIN
SELECT TABLE_PK_SEQ.NEXTVAL
INTO :new.PK
FROM dual;
END;

Create a procedure to copy some records from a table to another

I'm trying to create a simple procedure to copy some records from Table1 to Table2.
Table1:
id number PK
operation varchar2(50)
position varchar2(50)
code_operation varchar2(50) FK
Table2:
code_operation varchar2(50) PK
operation varchar2(50)
position varchar2(50)
client_number varchar2(50)
Starting from the client_number I have to copy the associated operation and position from Table1 and insert into operation and position of Table2.
I've tried this code but it doesn't work:
CREATE OR REPLACE PROCEDURE COPY_DATA(
BEGIN
DECLARE P_CLIENT_NUMBER VARCHAR2(50);
DECLARE P_CODE_OPERATION VARCHAR2(50);
DECLARE P_DIVISION VARCHAR2(50);
DECLARE P_POSITION VARCHAR2(50)
SELECT CODE_OPERATION INTO P_CODE_OPERATION FROM TABLE2;
SELECT CLIENT_NUMBER INTO P_CLIENT_NUMBER FROM TABLE2;
SELECT DIVISION INTO P_DIVISION FROM TABLE1;
SELECT POSITION INTO P_POSITION FROM TABLE1;
INSERT INTO TABLE2(DIVISION,POSITION)
WHERE CODE_OPERATION=P_COD_OPERATION;
END
);
I've got this error ERROR PLS-00103: Encountered the symbol “DECLARE” but I don't understand why, plus with this error I don't know if my code is correct or not.
Error you got is easy to fix. PL/SQL block has declare-begin-exception-end structure, which means that you first declare variables (in a stored procedure, you don't use declare keyword; strange enough, for triggers - which as kind of stored as well - you do use it). For example:
create or replace procedure copy_data as
p_client_number table2.client_number%type;
begin
select client_number
into p_client_number
from table2;
exception
when too_many_rows then
raise;
end;
However, without WHERE clause (or an aggregate, such as MIN or MAX), this will raise too_many_rows exception because it'll try to fetch all client numbers into a scalar variable, and that won't work. I included the way which shows how to handle it. What will you really do? Restrict number of rows to 1. Similarly, you'd handle no_data_found or other exceptions.
What you described looks strange to me.
you want to insert into table2 - which is a master table
values you'd insert are in table1 - which is a detail table
Looking at tables, I'd say that it should be vice versa.
insert into table1 (id, operation, position, code_operation)
select seq.nextval,
b.operation,
b.position,
b.code_operation
from table2 b
where b.client_number = 'ABC';
(I presumed that primary key is populated via a sequence.)
It also means that none of variables you declared is necessary. But, the procedure would accept client number as a parameter.
The whole procedure would then be:
create or replace procedure copy_data
(par_client_number in table2.client_number%type)
is
begin
insert into table1 (id, operation, position, code_operation)
select seq.nextval,
b.operation,
b.position,
b.code_operation
from table2 b
where b.client_number = par_client_number;
end;
You'd call it as
begin
copy_data('ABC');
end;
/

VARCHAR Leading 0's are lost when executing PLSQL procedures

I have a PL/SQL script which executes a number of procedures on an oracle DB.
The script defines:
DECLARE
productkey VARCHAR2(100);
BEGIN
productKey := '000000000070307037';
...
ProcedureName(productKey);
The procedure expects a VARCHAR2
PROCEDURE ProcedureName (
productKey VARCHAR2
)
The procedure inserts into a table:
BEGIN
Insert into Mytable
(
THIS_PRODUCT_KEY
)
Values
(productKey);
When I query that table, the product Key = 70307037, ie the leading 0's have been lost.
I saw some similar questions where TO_CHAR was suggested, I tried defining productKey in the script using TO_CHAR, and also modifiying the procedure to write using TO_CHAR:
BEGIN
Insert into Mytable
(
THIS_PRODUCT_KEY
)
Values
(TO_CHAR(productKey,'000000000000000000'));
Still coming through without the leading 0's.
There are multiple queries that join using the product key and don't work when the 0's are missing.
Why would I lose the 0's when the variable is a VARCHAR ?
I believe that "THIS_PRODUCT_KEY" column in your "Mytable" table is not a varchar2 column. I think it is number. If you change the datatype of the "THIS_PRODUCT_KEY" column to varchar2, it won't lose the 0s.

ORA-00907: missing right parenthesis on create table query [duplicate]

It appears that there is no concept of AUTO_INCREMENT in Oracle, up until and including version 11g.
How can I create a column that behaves like auto increment in Oracle 11g?
There is no such thing as "auto_increment" or "identity" columns in Oracle as of Oracle 11g. However, you can model it easily with a sequence and a trigger:
Table definition:
CREATE TABLE departments (
ID NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
CREATE SEQUENCE dept_seq START WITH 1;
Trigger definition:
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON departments
FOR EACH ROW
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
/
UPDATE:
IDENTITY column is now available on Oracle 12c:
create table t1 (
c1 NUMBER GENERATED by default on null as IDENTITY,
c2 VARCHAR2(10)
);
or specify starting and increment values, also preventing any insert into the identity column (GENERATED ALWAYS) (again, Oracle 12c+ only)
create table t1 (
c1 NUMBER GENERATED ALWAYS as IDENTITY(START with 1 INCREMENT by 1),
c2 VARCHAR2(10)
);
Alternatively, Oracle 12 also allows to use a sequence as a default value:
CREATE SEQUENCE dept_seq START WITH 1;
CREATE TABLE departments (
ID NUMBER(10) DEFAULT dept_seq.nextval NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
SYS_GUID returns a GUID-- a globally unique ID. A SYS_GUID is a RAW(16). It does not generate an incrementing numeric value.
If you want to create an incrementing numeric key, you'll want to create a sequence.
CREATE SEQUENCE name_of_sequence
START WITH 1
INCREMENT BY 1
CACHE 100;
You would then either use that sequence in your INSERT statement
INSERT INTO name_of_table( primary_key_column, <<other columns>> )
VALUES( name_of_sequence.nextval, <<other values>> );
Or you can define a trigger that automatically populates the primary key value using the sequence
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
SELECT name_of_sequence.nextval
INTO :new.primary_key_column
FROM dual;
END;
If you are using Oracle 11.1 or later, you can simplify the trigger a bit
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:new.primary_key_column := name_of_sequence.nextval;
END;
If you really want to use SYS_GUID
CREATE TABLE table_name (
primary_key_column raw(16) default sys_guid() primary key,
<<other columns>>
)
In Oracle 12c onward you could do something like,
CREATE TABLE MAPS
(
MAP_ID INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL,
MAP_NAME VARCHAR(24) NOT NULL,
UNIQUE (MAP_ID, MAP_NAME)
);
And in Oracle (Pre 12c).
-- create table
CREATE TABLE MAPS
(
MAP_ID INTEGER NOT NULL ,
MAP_NAME VARCHAR(24) NOT NULL,
UNIQUE (MAP_ID, MAP_NAME)
);
-- create sequence
CREATE SEQUENCE MAPS_SEQ;
-- create tigger using the sequence
CREATE OR REPLACE TRIGGER MAPS_TRG
BEFORE INSERT ON MAPS
FOR EACH ROW
WHEN (new.MAP_ID IS NULL)
BEGIN
SELECT MAPS_SEQ.NEXTVAL
INTO :new.MAP_ID
FROM dual;
END;
/
Here are three flavors:
numeric. Simple increasing numeric value, e.g. 1,2,3,....
GUID. globally univeral identifier, as a RAW datatype.
GUID (string). Same as above, but as a string which might be easier to handle in some languages.
x is the identity column. Substitute FOO with your table name in each of the examples.
-- numerical identity, e.g. 1,2,3...
create table FOO (
x number primary key
);
create sequence FOO_seq;
create or replace trigger FOO_trg
before insert on FOO
for each row
begin
select FOO_seq.nextval into :new.x from dual;
end;
/
-- GUID identity, e.g. 7CFF0C304187716EE040488AA1F9749A
-- use the commented out lines if you prefer RAW over VARCHAR2.
create table FOO (
x varchar(32) primary key -- string version
-- x raw(32) primary key -- raw version
);
create or replace trigger FOO_trg
before insert on FOO
for each row
begin
select cast(sys_guid() as varchar2(32)) into :new.x from dual; -- string version
-- select sys_guid() into :new.x from dual; -- raw version
end;
/
update:
Oracle 12c introduces these two variants that don't depend on triggers:
create table mytable(id number default mysequence.nextval);
create table mytable(id number generated as identity);
The first one uses a sequence in the traditional way; the second manages the value internally.
Oracle Database 12c introduced Identity, an auto-incremental (system-generated) column.
In the previous database versions (until 11g), you usually implement an Identity by creating a Sequence and a Trigger.
From 12c onward, you can create your own Table and define the column that has to be generated as an Identity.
Assuming you mean a column like the SQL Server identity column?
In Oracle, you use a SEQUENCE to achieve the same functionality. I'll see if I can find a good link and post it here.
Update: looks like you found it yourself. Here is the link anyway:
http://www.techonthenet.com/oracle/sequences.php
Trigger and Sequence can be used when you want serialized number that anyone can easily read/remember/understand. But if you don't want to manage ID Column (like emp_id) by this way, and value of this column is not much considerable, you can use SYS_GUID() at Table Creation to get Auto Increment like this.
CREATE TABLE <table_name>
(emp_id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(30));
Now your emp_id column will accept "globally unique identifier value".
you can insert value in table by ignoring emp_id column like this.
INSERT INTO <table_name> (name) VALUES ('name value');
So, it will insert unique value to your emp_id Column.
Starting with Oracle 12c there is support for Identity columns in one of two ways:
Sequence + Table - In this solution you still create a sequence as you normally would, then you use the following DDL:
CREATE TABLE MyTable
(ID NUMBER DEFAULT MyTable_Seq.NEXTVAL,
...)
Table Only - In this solution no sequence is explicitly specified. You would use the following DDL:
CREATE TABLE MyTable (ID NUMBER GENERATED AS IDENTITY, ...)
If you use the first way it is backward compatible with the existing way of doing things. The second is a little more straightforward and is more inline with the rest of the RDMS systems out there.
it is called Identity Columns and it is available only from oracle Oracle 12c
CREATE TABLE identity_test_tab
(
id NUMBER GENERATED ALWAYS AS IDENTITY,
description VARCHAR2 (30)
);
example of insert into Identity Columns as below
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION');
1 row created.
you can NOT do insert like below
INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION');
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION');
ERROR at line 1: ORA-32795: cannot insert into a generated always
identity column
useful link
Here is complete solution w.r.t exception/error handling for auto increment, this solution is backward compatible and will work on 11g & 12c, specifically if application is in production.
Please replace 'TABLE_NAME' with your appropriate table name
--checking if table already exisits
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME';
EXCEPTION WHEN OTHERS THEN NULL;
END;
/
--creating table
CREATE TABLE TABLE_NAME (
ID NUMBER(10) PRIMARY KEY NOT NULL,
.
.
.
);
--checking if sequence already exists
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE TABLE_NAME_SEQ';
EXCEPTION WHEN OTHERS THEN NULL;
END;
--creating sequence
/
CREATE SEQUENCE TABLE_NAME_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 1 NOMAXVALUE NOCYCLE CACHE 2;
--granting rights as per required user group
/
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE_NAME TO USER_GROUP;
-- creating trigger
/
CREATE OR REPLACE TRIGGER TABLE_NAME_TS BEFORE INSERT OR UPDATE ON TABLE_NAME FOR EACH ROW
BEGIN
-- auto increment column
SELECT TABLE_NAME_SEQ.NextVal INTO :New.ID FROM dual;
-- You can also put some other required default data as per need of your columns, for example
SELECT SYS_CONTEXT('USERENV', 'SESSIONID') INTO :New.SessionID FROM dual;
SELECT SYS_CONTEXT('USERENV','SERVER_HOST') INTO :New.HostName FROM dual;
SELECT SYS_CONTEXT('USERENV','OS_USER') INTO :New.LoginID FROM dual;
.
.
.
END;
/
Query to create auto increment in oracle. In below query incrmnt column value will be auto incremented wheneever a new row is inserted
CREATE TABLE table1(
id RAW(16) NOT NULL ENABLE,
incrmnt NUMBER(10,0) GENERATED ALWAYS AS IDENTITY
MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOORDER NOCYCLE NOT NULL ENABLE,
CONSTRAINT PK_table1 PRIMARY KEY (id) ENABLE);
This is how I did this on an existing table and column (named id):
UPDATE table SET id=ROWNUM;
DECLARE
maxval NUMBER;
BEGIN
SELECT MAX(id) INTO maxval FROM table;
EXECUTE IMMEDIATE 'DROP SEQUENCE table_seq';
EXECUTE IMMEDIATE 'CREATE SEQUENCE table_seq START WITH '|| TO_CHAR(TO_NUMBER(maxval)+1) ||' INCREMENT BY 1 NOMAXVALUE';
END;
CREATE TRIGGER table_trigger
BEFORE INSERT ON table
FOR EACH ROW
BEGIN
:new.id := table_seq.NEXTVAL;
END;
FUNCTION GETUNIQUEID_2 RETURN VARCHAR2
AS
v_curr_id NUMBER;
v_inc NUMBER;
v_next_val NUMBER;
pragma autonomous_transaction;
begin
CREATE SEQUENCE sequnce
START WITH YYMMDD0000000001
INCREMENT BY 1
NOCACHE
select sequence.nextval into v_curr_id from dual;
if(substr(v_curr_id,0,6)= to_char(sysdate,'yymmdd')) then
v_next_val := to_number(to_char(SYSDATE+1, 'yymmdd') || '0000000000');
v_inc := v_next_val - v_curr_id;
execute immediate ' alter sequence sequence increment by ' || v_inc ;
select sequence.nextval into v_curr_id from dual;
execute immediate ' alter sequence sequence increment by 1';
else
dbms_output.put_line('exception : file not found');
end if;
RETURN 'ID'||v_curr_id;
END;
FUNCTION UNIQUE2(
seq IN NUMBER
) RETURN VARCHAR2
AS
i NUMBER := seq;
s VARCHAR2(9);
r NUMBER(2,0);
BEGIN
WHILE i > 0 LOOP
r := MOD( i, 36 );
i := ( i - r ) / 36;
IF ( r < 10 ) THEN
s := TO_CHAR(r) || s;
ELSE
s := CHR( 55 + r ) || s;
END IF;
END LOOP;
RETURN 'ID'||LPAD( s, 14, '0' );
END;
Creating a Sequence:
CREATE SEQUENCE SEQ_CM_LC_FINAL_STATUS
MINVALUE 1 MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE;
Adding a Trigger
CREATE OR REPLACE TRIGGER CM_LC_FINAL_STATUS_TRIGGER
BEFORE INSERT
ON CM_LC_FINAL_STATUS
FOR EACH ROW
BEGIN
:NEW.LC_FINAL_STATUS_NO := SEQ_CM_LC_FINAL_STATUS.NEXTVAL;
END;
The first step is to create a SEQUENCE in your database, which is a data object that multiple users can access to automatically generate incremented values. As discussed in the documentation, a sequence in Oracle prevents duplicate values from being created simultaneously because multiple users are effectively forced to “take turns” before each sequential item is generated. –
Finally, we’ll create our SEQUENCE that will be utilized later to actually generate the unique, auto incremented value. –
While we have our table created and ready to go, our sequence is thus far just sitting there but never being put to use. This is where TRIGGERS come in. Similar to an event in modern programming languages, a TRIGGER in Oracle is a stored procedure that is executed when a particular event occurs. Typically a TRIGGER will be configured to fire when a table is updated or a record is deleted, providing a bit of cleanup when necessary. –
In our case, we want to execute our TRIGGER prior to INSERT into our CM_LC_FINAL_STATUS table, ensuring our SEQUENCE is incremented and that new value is passed onto our primary key column.
create trigger t1_trigger
before insert on AUDITLOGS
for each row
begin
select t1_seq.nextval into :new.id from dual;
end;
only I have to just change the table name (AUDITLOGS) with your table name and new.id with new.column_name
oracle has sequences AND identity columns in 12c
http://www.oracle-base.com/articles/12c/identity-columns-in-oracle-12cr1.php#identity-columns
I found this but not sure what rdb 7 is
http://www.oracle.com/technetwork/products/rdb/0307-identity-columns-128126.pdf
Maybe just try this simple script:
http://www.hlavaj.sk/ai.php
Result is:
CREATE SEQUENCE TABLE_PK_SEQ;
CREATE OR REPLACE TRIGGER TR_SEQ_TABLE BEFORE INSERT ON TABLE FOR EACH ROW
BEGIN
SELECT TABLE_PK_SEQ.NEXTVAL
INTO :new.PK
FROM dual;
END;

How to programmatically set table name in PL/SQL?

I created the following simple PL/SQL stored procedure example to ask a specific question. This procedure inserts an employee name and id number into a table called employees_???. The ??? is explained below.
PROCEDURE hire_employee (emp_id IN INTEGER, name IN VARCHAR2, country IN VARCHAR2)
AS
BEGIN
INSERT INTO employees_??? VALUES (emp_id, name, 1000);
END hire_employee;
What I need is to set the table name based on the IN variable country. For example,
If country = 'usa', I want the INSERT line to read:
INSERT INTO employees_usa VALUES (emp_id, name, 1000);
If country = 'germany', I want the INSERT line to read:
INSERT INTO employees_germany VALUES (emp_id, name, 1000);
If country = 'france', I want the INSERT line to read:
INSERT INTO employees_france VALUES (emp_id, name, 1000);
etc...
Is there a way to do this in PL/SQL by substituting something in place of employee_??? so only one line of code for INSERT is used? Or is using a case or if/then/else statement the best way?
To answer your question, you have to use execute immediate and create your statement dynamically.
create or replace procedure hire_employee (
emp_id IN INTEGER
, name IN VARCHAR2
, country IN VARCHAR2 ) is
-- maximum length of an object name in Oracle is 30
l_table_name varchar2(30) := 'employees_' || country;
begin
execute immediate 'insert into ' || l_table_name
|| ' values (:1, :2, 1000)'
using emp_id, name;
end hire_employee;
However, this is a massively over-complicated way of storing the data. If you want to select all data you have to union large numbers of tables.
It would be far better to normalise the database properly and add country to an employees table.
Something like the following:
create table employees (
emp_id number(16)
, country varchar2(3) -- ISO codes
, name varchar2(4000) -- maximum who knows what name people might have
, < other_columns >
, constraint pk_employees primary key ( emp_id )
);
Your procedure then becomes a very simple insert statement:
create or replace procedure hire_employee (
emp_id in integer
, name in varchar2
, country in varchar2 ) is
insert into employees
values ( emp_id, country, name, 1000 );
end hire_employee;
You can use dynamic SQL and the EXECUTE IMMEDIATE construct. In this, you construct the query as a string and then execute it. A good example is at http://docs.oracle.com/cd/B10500_01/appdev.920/a96590/adg09dyn.htm

Resources