Reputation: 109
I have the following SQL code:
INSERT INTO TIMES (saleDay, dayType)
SELECT saleDate, CASE WHEN h.hd IS NOT NULL THEN 'Holiday'
WHEN to_char(saleDate, 'd') IN (1,7) THEN 'Weekend'
ELSE 'Weekday' END dayType
FROM SALES s LEFT JOIN
(SELECT '01.01' hd FROM DUAL UNION ALL
SELECT '15.01' FROM DUAL UNION ALL
SELECT '19.01' FROM DUAL UNION ALL
SELECT '28.05' FROM DUAL UNION ALL
SELECT '04.07' FROM DUAL UNION ALL
SELECT '08.10' FROM DUAL UNION ALL
SELECT '11.11' FROM DUAL UNION ALL
SELECT '22.11' FROM DUAL UNION ALL
SELECT '25.12' FROM DUAL) h
ON h.hd = TO_CHAR(s.saleDate, 'dd.mm');
And I need to convert it to a PL/SQL block. I initially just turned the code above into a create or replace procedure and then called it, but I've been asked to complete the code above in PL/SQL.
Unfortunately, I've really struggled in this area and am still trying to grasp the concept of PL/SQL, especially in situations like this where it doesn't make much sense to conduct the INSERT code via PL/SQL. Any pointers/instruction on what the best way to convert this to PL/SQL is?
Thank you!
Upvotes: 0
Views: 2767
Reputation: 9091
I agree, this is better as plain SQL. If this is just for a course, I'd do it with a simple loop and a collection. If you're dealing with a high-volume production environment, a BULK COLLECT .. FORALL approach will have much better performance.
declare
vDayType varchar2(10);
TYPE Holidays is table of varchar2(5);
hd Holidays := Holidays('01.01','15.01','19.01','28.05','04.07','08.10','11.11','22.11','25.12');
begin
for s in (select distinct saleDate from Sales) loop
vDayType := case when TO_CHAR(s.saleDate, 'dd.mm') member of hd then
'Holiday'
when to_char(s.saleDate, 'd') IN (1,7) then
'Weekend'
else
'Weekday'
end;
insert into times (saleDay, dayType) values (s.saleDate, vDayType);
end loop;
end;
/
I feel like PL/SQL procedures like this are a good choice when so much processing needs to be done for each record that it would be awkward, less readable, or impossible to do in SQL. Maybe you're building HTML or modifying a DOCX file in a clob column. I don't know. Honestly, I don't come across use cases for this kind of thing very often in my work.
Upvotes: 2
Reputation: 1157
if TIMES table has only two columns (salesDay and DayType), you can also do it like this,
BEGIN
FOR rec IN
(SELECT saleDate, CASE WHEN h.hd IS NOT NULL THEN 'Holiday'
WHEN to_char(saleDate, 'd') IN (1,7) THEN 'Weekend'
ELSE 'Weekday' END dayType
FROM SALES s LEFT JOIN
(SELECT '01.01' hd FROM DUAL UNION ALL
SELECT '15.01' FROM DUAL UNION ALL
SELECT '19.01' FROM DUAL UNION ALL
SELECT '28.05' FROM DUAL UNION ALL
SELECT '04.07' FROM DUAL UNION ALL
SELECT '08.10' FROM DUAL UNION ALL
SELECT '11.11' FROM DUAL UNION ALL
SELECT '22.11' FROM DUAL UNION ALL
SELECT '25.12' FROM DUAL) h
ON h.hd = TO_CHAR(s.saleDate, 'dd.mm')))
LOOP
INSERT INTO TIMES VALUES rec;
END LOOP;
END;
/
Upvotes: 1
Reputation:
I don't have your tables, but I would do something like I am showing below - creating a table to accept the inserts (similar to yours) and using HIREDATE from the EMP table in the SCOTT schema.
I see that kfinity just posted a similar answer; I am still posting mine because I feel it is cleaner, but it's really the same answer.
Also: keeping the dates in a nested table, as kfinity has done, is the correct approach (declare all the "magic things" at the top of your code, so they are easy to find and modify if/when needed); however, it is possible that in your course you haven't covered collections yet. In my solution I hard-coded the values directly where they were needed.
drop table my_table purge;
create table my_table ( hireday date, daytype varchar2(20) );
begin
for r in ( select hiredate from scott.emp )
loop
insert into my_table ( hireday, daytype ) values
( r.hiredate,
case when to_char(r.hiredate, 'dd.mm') in (
'01.01', '15.01', '19.01', '28.05', '04.07',
'08.10', '11.11', '22.11', '25.12') then 'Holiday'
when to_char(r.hiredate, 'd') in ('1', '7') then 'Weekend'
else 'Weekday' end
);
end loop;
end;
/
Upvotes: 0
Reputation: 109
Thinking I may just go with this...Although I'm not sure if it'll be taken as PL/SQL.
Better solutions are still welcomed!
BEGIN
INSERT INTO TIMES (saleDay, dayType)
SELECT saleDate, CASE WHEN h.hd IS NOT NULL THEN 'Holiday'
WHEN to_char(saleDate, 'd') IN (1,7) THEN 'Weekend'
ELSE 'Weekday' END dayType
FROM SALES s LEFT JOIN
(SELECT '01.01' hd FROM DUAL UNION ALL
SELECT '15.01' FROM DUAL UNION ALL
SELECT '19.01' FROM DUAL UNION ALL
SELECT '28.05' FROM DUAL UNION ALL
SELECT '04.07' FROM DUAL UNION ALL
SELECT '08.10' FROM DUAL UNION ALL
SELECT '11.11' FROM DUAL UNION ALL
SELECT '22.11' FROM DUAL UNION ALL
SELECT '25.12' FROM DUAL) h
ON h.hd = TO_CHAR(s.saleDate, 'dd.mm');
END;
/
Upvotes: 1