PL/SQL for 3 different tables [message #597080] |
Mon, 30 September 2013 14:57 |
Ricky_1362002
Messages: 111 Registered: February 2009
|
Senior Member |
|
|
I am a DBA but for some reason, I have been requested to write a PL/SQL procedure to get the following:
Below are the tables:
Table - CONFI Table - DEPT Table - PER_DEPT
ID Name Dept_ID Dept_ID Desc Dept_ID Level
1 Tom 100 100 abc 100 3
2 Rick 100 101 def 100 4
3 Mary 101 102 acd 100 5
4 Cathy 101 101 1
5 Sarah 102 101 2
102 6
102 7
Table CONFI has the records entered wrongly by someone, it should have different Dept_ID for different Names.
Table DEPT has some description
Table PER_DEPT has some levels assigned to each dept, multiple levels are assigned to the same dept, that is how it is.
All the IDs are sequentially generated, using confi_seq.nextval(for ID) and dept_seq.nextval(for dept_id)
Confi table is to be updated in such a way that it should have different dept_id for different names
For example, here dept_id 100 is repeated 2 more times, so the dept table must be added with 2 more new dept_id values
starting with the nextval i.e. 103 and 104
And in the Per-Dept table, these new values must be inserted, with the same levels as with 100
The new tables should look like this:
Table - CONFI Table - DEPT Table - PER_DEPT
ID Name Dept_ID Dept_ID Desc Dept_ID Level
1 Tom 100 100 abc 100 3
2 Rick 103 101 def 100 4
3 Mary 101 102 acd 100 5
4 Cathy 104 103 abc 101 1
5 Sarah 102 104 def 101 2
102 6
102 7
103 3
103 4
103 5
104 1
104 2
I am trying to work on this but not really getting any good ideas as am a DBA and new to these PL/SQL Procedures, need your help please.
Thank you,
Rick
|
|
|
|
Re: PL/SQL for 3 different tables [message #597082 is a reply to message #597081] |
Mon, 30 September 2013 15:29 |
Ricky_1362002
Messages: 111 Registered: February 2009
|
Senior Member |
|
|
Well, I am a DBA and sorry for saying that I am new to PL/SQL, I do know quite a bit of it, but this one looks complicated to me, coz I think this involves cursors and so on, It has been quite long that I had worked on creating the PL/SQl procedures. For me, it looks much of a developers work here, but as I have been requested, I am trying to help them around, and thought of asking some people over here for suggestions and help.
I understand that this does NOT really looks like a real world application, but it is, the application for the folks here is built in such a way, and I cannot argue with the application team here, instead I thought I would try to help them if I can. And so posted here for the help/suggestions.
[Updated on: Mon, 30 September 2013 15:33] Report message to a moderator
|
|
|
Re: PL/SQL for 3 different tables [message #597083 is a reply to message #597080] |
Mon, 30 September 2013 15:33 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
Did you have a look at Merge statement. If you want to update one table at a time and also do the inserts, merge would suffice the requirement as plain SQL instead of using pl/sql. Any particular reason for choosing pl/sql over SQL, any bottleneck?
Regards,
Lalit
|
|
|
|
|
|
Re: PL/SQL for 3 different tables [message #597091 is a reply to message #597087] |
Mon, 30 September 2013 16:33 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
Alright then, it is much complex in plain SQL to do multiple updates. I call it to be multiple updates in your case since you want to update the duplicates with incremental sequence. A single update will set all the dept_id with a single value.
A hint for you to build a logic is -
1. Fetch the dept_ids from confi table which are duplicates.
2. Use it as a subquery to return only the records having duplicate dept_ids. Use analytic function, row_number to give rank to the duplicate dept_ids over partition by dept_id order by dept_id.
3. In a loop, update these dept_ids row by row and assign the next sequence value. It has to be row by row...hence slow.
4. Write and insert statement just after this update and insert the curr val (since value already incremented while it updated confi table) into the dept table.
5. Repeat the loop till there are no dupliactes.
This is what came across my mind right now. We can definitely improve it but only if you come up with your logic and code.
Regards,
Lalit
|
|
|
|
|
Re: PL/SQL for 3 different tables [message #597193 is a reply to message #597080] |
Tue, 01 October 2013 08:58 |
Ricky_1362002
Messages: 111 Registered: February 2009
|
Senior Member |
|
|
Quote:1) What is being done to prevent similar bad data from getting into these tables in the future?
They are doing some changes at the application level, to make sure that the data inserted would be correct from now on.
Quote:2) What PK/FK relationship exists on DEPT_ID between these 3 tables?
Dept_Id is the has an FK relation with both the other tables, and PK for the DEPT table.
Quote:3) From where does DEPT.DESC value originate when new rows are INSERTed into DEPT table?
Well, they are the pre-defined values and they don't change.
Quote:4) what is the criteria used to decide which row values remain unchanged & which rows get new values?
Sorry but I do not understand this question.
Quote:5) I saw many words explaining changes to PER_DEPT that I did not understand; especially the value for the LEVEL column
Oh, let me try explaining that again.
For one Dept_id there are many levels assigned, in this case-for dept_id=100 levels 3,4,5 are assigned, and since 100 has been repeated in CONFI table I would like to replace the second time 100 with the next dept_id (from the nextval), which is 103.
Now, 103 is the new dept_id, so it should have some levels (same as 100), and levels 3,4,5 should be assigned.
Please let me know if I was able to answer your questions or if you have any other questions.
Thank you BlackSwan.
Lalit, according to your logic does it also take care of the PER_DEPT table? I think we should add a few more steps. Well, I am still trying to get the desired results but being unsuccessful. Let me know if you can help me further.
Thanks
Rick
|
|
|
Re: PL/SQL for 3 different tables [message #597218 is a reply to message #597193] |
Tue, 01 October 2013 12:16 |
Ricky_1362002
Messages: 111 Registered: February 2009
|
Senior Member |
|
|
Ofcourse I am glad of BlackSwans suggestions and your inputs.
I am still trying but not able to get the desired results, coz I am poor in PL/SQL.
Here is the Logic I am trying - I am just giving you the pseudo code for understanding:
create table dept_id_repeats(dept_id number(5), counts number(5))
as
(select dept_id, count(*) as Counts
from CONFI
group by dept_id having count(*) > 1
order by dept_id)
The above will give us this table - dept_id_repeats:
Dept_id Counts
100 2
101 2
102 1
create or replace procedure UPDATE_CONF
is
cursor c1 is select counts from dept_id_repeats;
begin
n number:=100
if n=100
if c1.counts>1
insert into dept (dept_id,desc)
values (dept_seq.nextval, (select desc from dept where dept_id=n));
insert into per_dept(dept_id,level)
values(dept_seq.currval, (select level from per_dept where dept_id=n) -- > these will be multiple values and I dont really know how I can insert them)
end if;
n=n+1;
end;
end; ----end procedure
I know there are LOT of mistakes, but please bare with me. I need your help.
Thank you,
Rick
|
|
|
|
|
Re: PL/SQL for 3 different tables [message #597232 is a reply to message #597226] |
Tue, 01 October 2013 17:23 |
Ricky_1362002
Messages: 111 Registered: February 2009
|
Senior Member |
|
|
Well, here is what I tried. Please correct me if I am wrong.
create or replace procedure UPDATE_CONFI_TABLE
IS
cursor c1 is
SELECT name,dept_id,
ROW_NUMBER( ) OVER (PARTITION BY
dept_id ORDER BY dept_id
NULLS LAST) SRLNO
FROM confi;
dept1_rec confi%rowtype;
cursor c2 is
select * from dept;
dept2_rec dept%rowtype;
a number:=100
begin
open c1,c2;
loop
fetch c1 into dept1_rec;
fetch c2 into dept2_rec;
loop
if dept1_rec.dept_id=a and tid1_rec.srlno=2
then
insert into dept
select dept_seq.nextval,dept2_rec.desc
from dept where dept_id=&&a;
update confi set dept_id=dept_seq.currval
where dept_id=&&a and dept1_rec.srlno=2;
Insert INTO per_dept
select dept_seq.currval,level
from per_dept where dept_id=&&a;
end if;
end loop;
a=a+1;
end loop;
close c1,c2;
end;
/
|
|
|