Create Serial Number with a String in oracle - oracle

I am using the following code in oracle on create record trigger to create a serial number. I want my serial number like LM0001 . Using LM000 STRING WITH NUMBER and concat both to generate the serial number. I am getting error ora-06502. Need help where i am doing wrong. Where should i modify the code
DECLARE
VCAN varchar2(40);
L number (10);
BEGIN
SELECT MAX(SL_NO)INTO VCAN FROM LAND_MANAGEMENT;
IF VCAN > 0 THEN
L := VCAN + 1;
:LAND_MANAGEMENT.SL_NO := 'LM000' || L;
ELSE
:LAND_MANAGEMENT.SL_NO := 'LM000' || 1;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
:LAND_MANAGEMENT.SL_NO := 'LM000'|| 1;
END;

Solved the problem using sequence
create a sequence
CREATE SEQUENCE LMANAGEMENT_SEQ
START WITH 21
MAXVALUE 9999999999999999999999999999
MINVALUE 0
NOCYCLE
CACHE 20
NOORDER;
sql query in when-create-record trigger
select 'LM' || to_char(lmanagement_seq.nextval, '000000') INTO
:land_management.sl_no
from dual;

Related

Oracle: Update Every Row in a Table based off an Array

So i'm trying to create some seed data for a database that uses zip codes. I've created an array of 22 arbitrary zip code strings, and i'm trying to loop through the array and update one of the zips to every row in a table. Based on what I read and tried (I'm a 1st year, so I'm probably missing something), this should work, and does when I just output the array value based on the count of the table. this issue is in the row id subquery. When I run it in my console, it doesn't throw any errors, but it never completes and I think it's stuck in an infinite loop. How can I adjust this so that it will update the field and not get stuck?
declare
t_count NUMBER;
TYPE zips IS VARRAY(22) OF CHAR(5);
set_of_zips zips;
i NUMBER;
j NUMBER :=1;
BEGIN
SELECT count(*) INTO t_count FROM T_DATA;
set_of_zips:= zips('72550', '71601', '85920', '85135', '95451', '90021', '99611', '99928', '35213', '60475', '80451', '80023', '59330', '62226', '27127', '28006', '66515', '27620', '66527', '15438', '32601', '00000');
FOR i IN 1 .. t_count LOOP
UPDATE T_DATA
SET T_ZIP=set_of_zips(j)
---
WHERE rowid IN (
SELECT ri FROM (
SELECT rowid AS ri
FROM T_DATA
ORDER BY T_ZIP
)
) = i;
---
j := j + 1;
IF j > 22
THEN
j := 1;
END IF;
END LOOP;
COMMIT;
end;
You don't need PL/SQL for this.
UPDATE t_data
SET t_zip = DECODE(MOD(ROWNUM,22)+1,
1,'72550',
2,'71601',
3,'85920',
4,'85135',
5,'95451',
6,'90021',
7,'99611',
8,'99928',
9,'35213',
10,'60475',
11,'80451',
12,'80023',
13,'59330',
14,'62226',
15,'27127',
16,'28006',
17,'66515',
18,'27620',
19,'66527',
20,'15438',
21,'32601',
22,'00000')

Inserting values into a created table with while loop

I'm working on a while loop exercise on oracle. I have created a table with two columns.
What I want to do is; inserting values into first column with a sequence of from 1 to 1 million(1,2,3,4,5....1000000).
I've tried
DECLARE
a int := 0;
BEGIN
WHILE a < 1000000 LOOP
a := a + 1;
END LOOP;
END;
insert into Schema_name.table_name
(column_1)
values('a')
P.S: I'm working on Toad 12.9
Would you like to give a hand to me for this?
Just insert values(a), when you write 'a' you insert the character 'a' and not the variable a
DECLARE
a int := 0;
BEGIN
WHILE a < 1000000 LOOP
a := a + 1;
insert into Schema_name.table_name
(column_1)
values(a);
END LOOP;
END;

ORA-01555 error when updating 200 million rows with BULK COLLECT

I have the following PL/SQL code, which updates one column of each row in a table with about 200 million rows. I use BULK COLLECT to repeatedly fetch 150,000 rows from the table and update the rows. I do a commit after 50,000 updates.
DECLARE
CURSOR jobs_cursor IS
SELECT e.ID, e.PTI, e.CAT, e.JOBNAME, e.JOBDATE, e.WORK_DESCRIPTION
FROM JOB e
WHERE length(e.WORK_DESCRIPTION) > 1000;
TYPE JOBS_TYPE IS TABLE OF jobs_cursor%ROWTYPE;
v_jobs JOBS_TYPE;
fetch_jobs_limit PLS_INTEGER := 150000;
trimmed_work_description VARCHAR2(2000 CHAR);
sub_string_work_description_left VARCHAR2(1000 CHAR);
sub_string_work_description_right VARCHAR2(1000 CHAR);
update_counter NUMBER := 0;
commit_counter NUMBER := 50000;
BEGIN
OPEN jobs_cursor;
LOOP
FETCH jobs_cursor BULK COLLECT INTO v_jobs LIMIT fetch_jobs_limit;
EXIT WHEN v_jobs.COUNT = 0;
FOR idx IN 1..v_jobs.COUNT
LOOP
trimmed_work_description := ' ';
IF v_jobs(idx).WORK_DESCRIPTION IS NOT NULL THEN
trimmed_work_description := TRIM(TRAILING ' ' FROM v_jobs(idx).WORK_DESCRIPTION);
END IF;
IF length(trimmed_work_description) <= 1000 THEN
UPDATE JOBS j SET j.WORK_DESCRIPTION = trimmed_work_description WHERE j.ID = v_jobs(idx).ID;
update_counter := update_counter + 1;
IF mod(update_counter, commit_counter) = 0 THEN
COMMIT;
update_counter := 0;
END IF;
CONTINUE;
ELSIF length(trimmed_work_description) > 1000 THEN
sub_string_work_description_left := SUBSTR(trimmed_work_description, 1, 1000);
sub_string_work_description_right := SUBSTR(trimmed_work_description, 1001, 2000);
END IF;
UPDATE JOBS j SET j.WORK_DESCRIPTION = sub_string_work_description_left WHERE j.ID = v_jobs(idx).ID;
INSERT INTO JOBS j VALUES ("SEQUENCE_JOBS".NEXTVAL, j.PTI, j.CAT, j.JOBNAME, j.JOBDATE, sub_string_work_description_right);
update_counter := update_counter + 1;
IF mod(update_counter, commit_counter) = 0 THEN
COMMIT;
update_counter := 0;
END IF;
END LOOP;
END LOOP;
COMMIT;
CLOSE jobs_cursor;
END;
The code runs for several hours, but then Oracle raises an ORA-01555 - Snapshot too old - Rollback segment number 14 with name xxxx too small.
Could you please tell me what is wrong with my PL/SQL? I already did the Google research and found some threads saying that this error could be avoided by expanding the UNDO table space, however this is not an option in my case. Thus, I need to modify the PL/SQL code.
On first view I don't see any reason why you make the update in a loop, it should be possible with single statements. Would be similar to this (not verified/tested)
update JOBS j SET
WORK_DESCRIPTION = SUBSTR(TRIM(TRAILING ' ' FROM WORK_DESCRIPTION), 1, 1000)
WHERE length(WORK_DESCRIPTION) > 1000;
INSERT INTO JOBS
SELECT SEQUENCE_JOBS.NEXTVAL, j.PTI, j.CAT, j.JOBNAME, j.JOBDATE,
SUBSTR(WORK_DESCRIPTION, 1001, 2000)
FROM JOBS j
WHERE length(TRIM(TRAILING ' ' FROM WORK_DESCRIPTION)) > 1000;

Recuperate Non inserted rows Oracle

I have 10.000 rows to insert into a table.
For an Insert With FORALL in oracle...
FORALL x IN TABLE_NAME.First .. TABLE_NAME.Last
INSERT
INTO TABLE_NAME VALUES
(
TABLE_NAME(x).VAL1,
TABLE_NAME(x).VAL2,
TABLE_NAME(x).VAL3,
TABLE_NAME(x).VAL4,
TABLE_NAME(x).VAL5
);
How can I recover the data from rows that doesnt insert into table due violation of constrainst in order to insert those items in a non-typed table of rejected items?
You can use the save exceptions clause of the forall statement to collect the error(s), and then use the sql%bulk_exceptions implicit cursor attribute to see what actually happened. There's an example in that documentation, but in your case you can do (using a made up table and data):
create table your_table (val1 number primary key, val2 number, val3 number, val4 number, val5 number);
declare
type l_table_type is table of your_table%rowtype;
l_table l_table_type := l_table_type();
dml_errors exception;
pragma exception_init(dml_errors, -24381);
begin
l_table.extend;
l_table(l_table.count).val1 := 1;
l_table(l_table.count).val2 := 1.2;
l_table(l_table.count).val3 := 1.3;
l_table(l_table.count).val4 := 1.4;
l_table(l_table.count).val5 := 1.5;
l_table.extend;
l_table(l_table.count).val1 := 2;
l_table(l_table.count).val2 := 2.2;
l_table(l_table.count).val3 := 2.3;
l_table(l_table.count).val4 := 2.4;
l_table(l_table.count).val5 := 2.5;
l_table.extend;
l_table(l_table.count).val1 := 1;
l_table(l_table.count).val2 := 3.2;
l_table(l_table.count).val3 := 3.3;
l_table(l_table.count).val4 := 3.4;
l_table(l_table.count).val5 := 3.5;
forall x in l_table.first .. l_table.last save exceptions
insert
into your_table values
(
l_table(x).val1,
l_table(x).val2,
l_table(x).val3,
l_table(x).val4,
l_table(x).val5
);
exception
when dml_errors then
for i in 1..sql%bulk_exceptions.count loop
dbms_output.put_line('Index ' || sql%bulk_exceptions(i).error_index
|| ' error ' || -sql%bulk_exceptions(i).error_code);
dbms_output.put_line(' val1: ' || l_table(sql%bulk_exceptions(i).error_index).val1);
dbms_output.put_line(' val2: ' || l_table(sql%bulk_exceptions(i).error_index).val2);
dbms_output.put_line(' val3: ' || l_table(sql%bulk_exceptions(i).error_index).val3);
dbms_output.put_line(' val4: ' || l_table(sql%bulk_exceptions(i).error_index).val4);
dbms_output.put_line(' val5: ' || l_table(sql%bulk_exceptions(i).error_index).val5);
end loop;
end;
/
That produces the output:
PL/SQL procedure successfully completed.
Index 3 error -1
val1: 1
val2: 3.2
val3: 3.3
val4: 3.4
val5: 3.5
The first collection element with val1 set to one was inserted successfully; the second one got the unique constraint exception and was not - but it was put into the bulk exception mechanism instead of causing the entire statement to fail.
You can then decide whether to raise an exception (or re-raise), or immediately roll back (possibly to a savepoint); or commit the inserts that did not error.
You can also insert the same values into your table of rejected items, but you'd need to be a bit careful if you're rolling back other changes (presumably you wouldn't be in that scenario though).
You can't directly use another forall to do that - referring to l_table(sql%bulk_exceptions(i).error_index).val1 inside the values() clause throws ORA-00911 because of the % character - so you'd either have to do individual inserts inside the for loop, or copy the values to another collection and bulk-insert from that. Unless you are expecting a lot of rejections individual inserts might be good enough.

Oracle - Set the sequence value to max indentity value of the table within trigger

I need to get the max indentity value from the table and set the sequence to that value.
For that I'm trying to read max indentity value from the table(on which current trigger is fired) within this trigger and set the sequence to that value
But Im getting mutating error when going to read the table. Im using Oracle 11g.
So my problem is there any way to set the sequence value to max indentity value of the table within this trigger? Please advice.
Here is my trigger ;
create or replace
TRIGGER StringTextTrg BEFORE INSERT ON StringText
FOR EACH ROW
DECLARE
v_newVal NUMBER(12) := 0;
v_incval NUMBER(12) := 0;
BEGIN
IF INSERTING AND :new.STxtID IS NULL THEN
SELECT StringText_STxtID_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
-- If this is the first time this table have been inserted into (sequence == 1)
IF v_newVal = 1 THEN
--get the max indentity value from the table
SELECT NVL(max(STxtID),0) INTO v_newVal FROM StringText;
v_newVal := v_newVal + 1;
--set the sequence to that value
LOOP
EXIT WHEN v_incval>=v_newVal;
SELECT StringText_STxtID_SEQ.nextval INTO v_incval FROM dual;
END LOOP;
END IF;
-- assign the value from the sequence to emulate the identity column
:new.STxtID := v_newVal;
END IF;
END;
The following is my answer, using which is something I am strongly against:
CREATE OR REPLACE TRIGGER StringTextTrg
BEFORE INSERT
ON StringText
FOR EACH ROW
DECLARE
v_newVal NUMBER (12) := 0;
v_incval NUMBER (12) := 0;
BEGIN
IF INSERTING AND :new.STxtID IS NULL THEN
SELECT StringText_STxtID_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
-- If this is the first time this table have been inserted into (sequence == 1)
IF v_newVal = 1 THEN
--get the max indentity value from the table
SELECT NVL (MAX (STxtID), 0) INTO v_newVal FROM StringText;
v_newVal := v_newVal + 1;
--set the sequence to that value
EXECUTE IMMEDIATE ('DROP SEQUENCE StringText_STxtID_SEQ');
EXECUTE IMMEDIATE ('CREATE SEQUENCE StringText_STxtID_SEQ START WITH '||to_char(v_newVal));
END IF;
-- assign the value from the sequence to emulate the identity column
:new.STxtID := v_newVal;
END IF;
END;
/
Sequences are database objects. You cannot reset them, you have to drop and recreate them. Hence you have to (ab)use dynamic SQL for this job.
This is not the best practice for creating auto-generated sequential integer primary key column values. Moreover, consider forbidding manual entries to this column as those are certainly going to create chaos in the order you are trying to maintain.

Resources