update emp_id column with 1 billion records - oracle

I have an EMP table with columns
emp_id(number(10)), ename varchar2(25) and DOB (date)
The count of records = 1billion.
The emp_id column is totally null and I have to fill it with unique values.
What are the 3 easy steps to complete the task?
Help me with Oracle PL/SQL code to finish this task.

Only 2 steps:
ALTER TABLE emp DROP COLUMN emp_id;
ALTER TABLE emp ADD (emp_id NUMBER GENERATED ALWAYS AS IDENTITY);
db<>fiddle here
Again, 2 steps:
CREATE SEQUENCE emp__emp_id__seq;
UPDATE emp
SET emp_id = emp__emp_id__seq.NEXTVAL;
db<>fiddle here
One step:
If you have overwritten the column data then either ROLLBACK the last transaction or restore the data from backups.

The emp_id column is totally null and I have to fill it with unique values.
If you want to do it one-time-only, then just one step would do:
update emp set emp_id = rownum;
and that column will have unique values. You don't need PL/SQL (but be patient as 1 billion rows is quite a lot, it'll take time).
If you want to automatically populate it in the future, then it depends on database version you use. Before 12c, you'll have to use a sequence and a database trigger. In later versions, you can still use the same (sequence + trigger) or - as MT0 showed - identity column.

Related

to update a column details into base table 2 from column of staging table against the datails of column from base table 1

There's total of three tables involved. one header base table, one material
base table, one staging table.
I have created the staging table with 4 columns, the values will be
updated from csv uploaded, column 1 is batch_no, column 2 is for
attribute.
>header base table(h) has batch_no and batch_id
>material base table(m) has batch_id, attr_m (empty, to be updated)
>staging table(s) has batch_no and attr_s
create table he (BATCH_ID number, BATCH_NO varchar2(30));
create table me (a6 varchar2(30), BATCH_id number);
create table s (batch_no varchar2(30), att varchar2(30));
I want to take values from attr_s and update attr_m against batch_no. How do I do that?
Here's my code, please help me fix this code, it doesn't work
update me
set a6 = (select att
from s where batch_no = (select he.batch_no
from he, s
where he.batch_no=s.batch_no))
error received:
single row subquery return multiple rows.
single row subquery return multiple rows
The update statement is applied to each individual row in ME. Therefore the assignment operation requires one scalar value to be returned from the subquery. Your subquery is returning multiple values, hence the error.
To fix this you need to further restrict the subquery so it returns one row for each row in ME. From your data model the only way to do this is with the BATCH_ID, like so:
update me
set a6 = (select att
from s where batch_no = (select he.batch_no
from he, s
where he.batch_no=s.batch_no
and he.batch_id = me.batch_id))
Such a solution will work providing that there is only one record in S which matches a given permutation of (batch_no, batch_id). As you have provided any sample data I can't verify that the above statement will actually solve your problem.

Automatically inserting data into a table using a procedure

I would like to ask you a rather easy question but I cannot get my head around it as I am a beginner in SQL.
My task is: Enter initial data into BankStats2 by inserting rows into BankStats2 that
contain the branch names together with how many loans are in the Loan
table for that branch name.
desc BankStats2
Name Null? Type
----------------------------------------- -------- ----------------------------
BRANCHNAME NOT NULL VARCHAR2(20)
NUMBEROFLOANS NUMBER(38)
desc Loan
Name Null? Type
----------------------------------------- -------- ----------------------------
CUSTOMERNAME CHAR(20)
BRANCHNAME CHAR(20)
AMOUNT NUMBER(38)
LOANNUMBER NOT NULL NUMBER(38)
select branchName,count(customerName) from Loan group by branchName;
BRANCHNAME COUNT(CUSTOMERNAME)
-------------------- -------------------
Yorkshire 3
RoyalBank 1
Midlands 3
Basically, I would like to insert this information in the BankStats2 table and the way I thought of doing it is by creating a procedure which I will show below.
CREATE OR REPLACE PROCEDURE PopulateBankStats AS
CURSOR someLoanRows IS
SELECT branchName,COUNT(customerName) FROM loan GROUP BY branchName;
aBranchNameRow loan.branchName%TYPE;
numberOfLoans INT;
BEGIN
OPEN someLoanRows;
LOOP
FETCH someLoanRows INTO aBranchNameRow, numberOfLoans;
INSERT INTO BankStats2 VALUES (aBranchNameRow,numberOfLoans);
EXIT WHEN someLoanRows%NOTFOUND;
END LOOP;
CLOSE someLoanRows;
END;
/
But executing it give me the following error:
ERROR at line 1:
ORA-00001: unique constraint (N0757934.SYS_C0034405) violated
ORA-06512: at "N0757934.POPULATEBANKSTATS", line 10
ORA-06512: at line 1
Any help would be greatly appreciated. Thank you for your time!
This insert fails: INSERT INTO BankStats2 VALUES (aBranchNameRow,numberOfLoans); due to the error: ORA-00001: unique constraint (N0757934.SYS_C0034405) violated
This means that there is an unique constraint created on some of the columns of the table BankStats2.
In order to find which column has unique constraint, run this query:
select * from USER_IND_COLUMNS where index_name = 'SYS_C0034405';
Your procedure is trying to insert a record with a value of this column which already is existing in the table.
Have a look on the INSERT statement.
What your procedure is doing is exactly this insert statement:
INSERT INTO BankStats2 (BRANCHNAME,NUMBEROFLOANS)
SELECT branchName,COUNT(customerName) FROM loan GROUP BY branchName;
It is always preferable to use SQL statement (if possible) instead of the PL/SQL cursor loop logik - search Tom Kyte's "row by row - slow by slow" for an explantion.
Even if you want to use a procedure at all cost - use this INSERT in the preocedure.
Your exception means that you try to insert a value of the column BRANCHNAME that already exists in the table BankStats2.
This could be by an accident or a systematic problem.
If it is an accident, simple clean the data, i.e. DELETE the row(s) with the corresponding keys from the BankStats2 table.
This query returns the values existing in both tables
select BRANCHNAME from BankStats2
intersect
select branchName FROM loan;
If you want to systematically avoid inserting the duplicated row, add this logik in your INSERT statement:
INSERT INTO BankStats2 (BRANCHNAME,NUMBEROFLOANS)
SELECT branchName,COUNT(customerName)
FROM loan
WHERE branchName IS NOT NULL
and branchName NOT IN (select BRANCHNAME from BankStats2)
GROUP BY branchName;
Note that the SELECT excludes the row with the value that already exists in the target table - using NOT IN (subquery).
Note also that I'm approaching your next possible problem. The column BRANCHNAME is non nullable in BankStats2, but is nullable (i.e. may contain NULL) in loan, so you would fail to insert the row with NULL to the table BankStats2. Therefore I exclude those rows with the branchName IS NOT NULL predicate.
If you want to process the existing keys with an UPDATE logik, check the MERGE statement.

How to increment the value of the unique constraint column value in ORACLE

How to increment the value of the unique constraint column value in ORACLE, in the select statement.
For example, in a table 'BILLING_TABLE' - column BLNG_Sk is the unique key (Autoincremented).
So while inserting a new record into the BILLING_TABLE, for the column BLNG_SK we need to give the value (Which is the increment by 1 from the present max value.)
For example, if BLNG_SK max value is 12321.
new record should be 12322.
how to achieve this in Oracle?
Oracle has a SEQUENCE object which provides the functionality you require.
You create one using the CREATE SEQUENCE SQL statement.
The Oracle documentation provides all the required information and the documentation is available via Oracle's Web site.
Assuming you are on Oracle 12.1 or later, define it as an identity column and do not pass any value when inserting:
create table testtable
( test_id number generated always as identity
constraint testtable_pk primary key
, othercol varchar2(10) );
insert into testtable (othercol) values ('Demo');
select * from testtable;
TEST_ID OTHERCOL
---------- ----------
1 Demo
insert into testtable (othercol) values ('Demo #2');
select * from testtable;
TEST_ID OTHERCOL
---------- ----------
1 Demo
2 Demo #2
Try creating a sequence and a trigger. This is the case when you provide the value manually.
CREATE SEQUENCE dept_seq START WITH 12322;
Trigger definition:
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON BILLING_TABLE
FOR EACH ROW
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
/

Trigger required to insert data [duplicate]

This question already has answers here:
Using sequential values for the primary key in an INSERT query
(2 answers)
Closed 9 years ago.
I am trying to load a column with unique sequence number each time a row of data is insrerted in the table.How can this be achieved?
You can create a Sequence, and then use the sequence nextval in your insert statements for the column which you want to have sequential incremented value.
CREATE SEQUENCE seq
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 10;
INSERT INTO tab VALUES (seq.nextval, col1, col2, col3);
there is nothing like "auto_increment" or "identity" in Oracle,
but if you want auto increment in your column value you can use Sequence for the this.
after creating sequence you can use After Insert Trigger to insert identical value.
here is trigger example...
CREATE OR REPLACE TRIGGER dep_ins_trig
BEFORE INSERT ON <table_name>
FOR EACH ROW
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
/
This is achieved by Trigger and Sequence 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.

Pattern to substitute for MERGE INTO Oracle syntax when not allowed

I have an application that uses the Oracle MERGE INTO... DML statement to update table A to correspond with some of the changes in another table B (table A is a summary of selected parts of table B along with some other info). In a typical merge operation, 5-6 rows (out of 10's of thousands) might be inserted in table B and 2-3 rows updated.
It turns out that the application is to be deployed in an environment that has a security policy on the target tables. The MERGE INTO... statement can't be used with these tables (ORA-28132: Merge into syntax does not support security policies)
So we have to change the MERGE INTO... logic to use regular inserts and updates instead. Is this a problem anyone else has run into? Is there a best-practice pattern for converting the WHEN MATCHED/WHEN NOT MATCHED logic in the merge statement into INSERT and UPDATE statements? The merge is within a stored procedure, so it's fine for the solution to use PL/SQL in addition to the DML if that is required.
Another way to do this (other than Merge) would be using two sql statements one for insert and one for update. The "WHEN MATCHED" and "WHEN NOT MATCHED" can be handled using joins or "in" Clause.
If you decide to take the below approach, it is better to run the update first (sine it only runs for the matching records) and then insert the non-Matching records. The Data sets would be the same either way, it just updates less number of records with the order below.
Also, Similar to the Merge, this update statement updates the Name Column even if the names in Source and Target match. If you dont want that, add that condition to the where as well.
create table src_table(
id number primary key,
name varchar2(20) not null
);
create table tgt_table(
id number primary key,
name varchar2(20) not null
);
insert into src_table values (1, 'abc');
insert into src_table values (2, 'def');
insert into src_table values (3, 'ghi');
insert into tgt_table values (1, 'abc');
insert into tgt_table values (2,'xyz');
SQL> select * from Src_Table;
ID NAME
---------- --------------------
1 abc
2 def
3 ghi
SQL> select * from Tgt_Table;
ID NAME
---------- --------------------
2 xyz
1 abc
Update tgt_Table tgt
set Tgt.Name =
(select Src.Name
from Src_Table Src
where Src.id = Tgt.id
);
2 rows updated. --Notice that ID 1 is updated even though value did not change
select * from Tgt_Table;
ID NAME
----- --------------------
2 def
1 abc
insert into tgt_Table
select src.*
from Src_Table src,
tgt_Table tgt
where src.id = tgt.id(+)
and tgt.id is null;
1 row created.
SQL> select * from tgt_Table;
ID NAME
---------- --------------------
2 def
1 abc
3 ghi
commit;
There could be better ways to do this, but this seems simple and SQL-oriented. If the Data set is Large, then a PL/SQL solution won't be as performant.
There are at least two options I can think of aside from digging into the security policy, which I don't know much about.
Process the records to merge row by row. Attempt to do the update, if it fails to update then insert, or vise versa, depending on whether you expect most records to need updating or inserting (ie optimize for the most common case that will reduce the number of SQL statements fired), eg:
begin
for row in (select ... from source_table) loop
update table_to_be_merged
if sql%rowcount = 0 then -- no row matched, so need to insert
insert ...
end if;
end loop;
end;
Another option may be to bulk collect the records you want to merge into an array, and then attempted to bulk insert them, catching all the primary key exceptions (I cannot recall the syntax for this right now, but you can get a bulk insert to place all the rows that fail to insert into another array and then process them).
Logically a merge statement has to check for the presence of each records behind the scenes anyway, and I think it is processed quite similarly to the code I posted above. However, merge will always be more efficient than coding it in PLSQL as it will be only 1 SQL call instead of many.

Resources