I need to call the stored function findtotalcarmodels from this PL/SQL block. The way this code is written is not the way I would do it in production, however it is an exercise in 'lateral' thinking.
SET SERVEROUTPUT ON FORMAT WRAP SIZE 12000
Declare
v_model VARCHAR2(40);
v_cost NUMBER;
v_reg VARCHAR2(10);
v_carcategory VARCHAR2(40);
v_totalcars NUMBER;
v_count DATE;
v_maxcount DATE;
v_maxdept VARCHAR2(20);
cursor carcur IS
SELECT * FROM i_car;
v_car carcur%ROWTYPE;
Cursor c_date (p_reg i_booking.registration%TYPE) IS
SELECT date_reserved
FROM i_booking
WHERE registration = p_reg;
v_date c_date%ROWTYPE;
Begin
v_totalcars := findtotalcarmodels();
FOR v_car IN carcur LOOP
If v_cost <=50000 THEN v_carcategory := 'Budget Car';
End IF;
If v_cost BETWEEN 50000 AND 100000 THEN v_carcategory := 'Standard Car';
End IF;
If v_cost >100000 THEN v_carcategory := 'Premium Car';
End If;
FOR v_date IN c_date(v_car.registration) LOOP
v_count := v_count + 1;
END LOOP;
IF v_count > v_maxcount THEN
v_maxcount := v_count;
v_maxdept := v_car.registration;
END IF;
DBMS_OUTPUT.PUT_LINE('Registration:'|| ' '|| v_car.registration);
DBMS_OUTPUT.PUT_LINE('Cost:'|| '$' ||v_car.Cost);
DBMS_OUTPUT.PUT_LINE('Model Name:'|| ' '||v_car.model_name);
DBMS_OUTPUT.PUT_LINE('Car Category:'|| ' '||v_carcategory);
DBMS_OUTPUT.PUT_LINE('Total number of Cars:'|| ' '||v_totalcars);
DBMS_OUTPUT.PUT_LINE('Most Recent Rental Date: '|| ' '||v_maxcount);
DBMS_OUTPUT.NEW_LINE;
END LOOP;
END;
I am getting the error:
v_totalcars := findtotalcarmodels();
*
ERROR at line 19:
ORA-06550: line 19, column 16:
PLS-00306: wrong number or types of arguments in call to 'FINDTOTALCARMODELS'
ORA-06550: line 19, column 1:
PL/SQL: Statement ignored
Am I calling my function correctly in the right position?
This is the function:
CREATE OR REPLACE Function findtotalcarmodels
(model_name_in IN varchar2)
RETURN NUMBER
IS
counter INTEGER := 0;
CURSOR car_count_cur IS
SELECT model_name FROM i_car WHERE model_name = model_name_in;
Rec_car_details car_count_cur%ROWTYPE;
BEGIN
OPEN car_count_cur;
LOOP
FETCH car_count_cur INTO Rec_car_details;
EXIT WHEN car_count_cur%NOTFOUND;
counter := counter + 1;
END LOOP;
CLOSE car_count_cur;
RETURN counter;
END;
Okay, so I have no idea why you're getting that error with that function. The error indicates that you're not giving the function the correct number of arguments. Judging by the function that's clearly not what's happening, or it's not the same function.
You've just changed the function call; the function requires an argument so the "incorrect" code you had in your first revision was actually correct.
However, let's put that to one side for a second and look again at what you're doing.
Your function is a count on a table. There's no need for a cursor or looping, incrementing variables or anything. You can simplify it to
select count(*) from i_car where model_name = :model_name
You never assign the variables v_count or v_maxcount a value so incrementing them will still result in a NULL. They're dates anyway, so it's a little strange to be incrementing them.
Your cursor c_date is just another count; once again no need for a loop.
The model_name variable is never initialised so your function will not return a result.
There are a lot of ways to simplify this; though I'm going to guess a few things here. Change your carcur cursor to the following:
select i.*
, case cost
when <= 50000 then 'Budget Car'
when <= 100000 then 'Standard Car'
else 'Premium Car'
end as category
, count(*) over ( partition by model_name ) as total_cars
from i_cars
This appears to enable you to remove your IF statements and your function. You can then remove your second loop by performing an outer join on i_booking (you need to add the primary key in yourself):
select i.*
, case c.cost
when <= 50000 then 'Budget Car'
when <= 100000 then 'Standard Car'
else 'Premium Car'
end as category
, count(distinct c.primary_key)
over ( partition by c.model_name ) as total_cars
, count(b.date_reserved)
over ( partition by b.registration ) as reserved_ct
from i_cars c
left outer join i_booking b
on c.registration = b.registration
I'm not 100% certain on the max stuff as it's not clear at all where it's assigned (it's not) but it looks as though you might be wanting to find the maximum count by model etc, in which case you can use a sub-query on the above cursor:
select sub.*
, max(total_cars) over () as max_cars
, max(reserved_ct) over () as max_reserved
from ( select i.*
, case c.cost
when <= 50000 then 'Budget Car'
when <= 100000 then 'Standard Car'
else 'Premium Car'
end as category
, count(distinct c.primary_key)
over ( partition by c.model_name ) as total_cars
, count(b.date_reserved)
over ( partition by b.registration ) as reserved_ct
from i_cars c
left outer join i_booking b
on c.registration = b.registration
) sub
If you then need to output it (there's rarely a need) you can loop through this single SQL statement, which gives you everything in one go:
declare
c_cursor is
select sub.*
, max(total_cars) over () as max_cars
, max(reserved_ct) over () as max_reserved
from ( select i.*
, case c.cost
when <= 50000 then 'Budget Car'
when <= 100000 then 'Standard Car'
else 'Premium Car'
end as category
, count(distinct c.primary_key)
over ( partition by c.model_name ) as total_cars
, count(b.date_reserved)
over ( partition by b.registration ) as reserved_ct
from i_cars c
left outer join i_booking b
on c.registration = b.registration
) sub
;
begin
for i in c_cursor loop
dbms_output.put_line(i.registration);
dbms_output.put_line(i.cost);
...
end loop;
end;
I've reduced a PL/SQL block and a function to a single SQL statement; it may not be spot on because there's so many unknowns but it's worth trying for yourself. Simple is almost always better.
Related
I'm writing a stored procedure for paginated results and this result can be ordered by certain values. I did have a switch case in a select statement but because it was trying to do an orderby on rownum it was very slow.
Now I am trying to use dyanmic sql to build the query outside the select but I don't know if what I am doing is possible.
Here is my SQL in Oracle SQL Developer:
create or replace PROCEDURE Sp_tsa_trainees_pagination (
schemeid IN INT,
searchval IN VARCHAR2,
pagesize IN INT DEFAULT 20,
currentpage IN INT DEFAULT 1,
--orderby IN VARCHAR2,
cursor_ OUT SYS_REFCURSOR)
AS
-- LOCAL VARIABLES
totalcount INT;
numberofpages INT;
startposition NUMBER;
endposition NUMBER;
orderby VARCHAR2(100) := 'surname asc' ;
dynamic_query VARCHAR(255) := 'row_number() over (order by t.SURNAME DESC, t.FORENAMES DESC) AS rnum';
BEGIN
-- Get total number of trainees in scheme
select COUNT(t.ORG_REGISTRATION_ID)
into totalcount FROM v_trainee t
where t.ORG_REGISTRATION_ID = schemeid
AND t.status = 'A' and LOWER(t.trainee_name) like '%' || LOWER(searchval) || '%';
-- calculate number of pages in the pagination by dividing total number of records by how many to display for each page
numberofpages := totalcount / pagesize;
-- get start position by multiplying number of records to display for each page by current page
startposition := pagesize *( currentpage-1);
-- add calculated start position by number of records to display to get end position
endposition := startposition + pagesize;
CASE orderby
WHEN 'surname desc' THEN dynamic_query := 'row_number() over (order by t.SURNAME DESC, t.FORENAMES DESC) AS rnum';
WHEN 'surname asc' THEN dynamic_query := 'row_number() over (order by t.SURNAME ASC, t.FORENAMES ASC) AS rnum';
END CASE;
OPEN cursor_ FOR
Select * from
(
SELECT
-- order by based on selection
dynamic_query rnum,
t.ORG_REGISTRATION_ID SearchId,
t.FORENAMES Forenames,
t.FORENAME Forename,
t.SURNAME Surname,
t.person_id PersonId,
t.trainee_name TraineeName,
t.STATUS Status,
t.IPD_ANNUAL_REVIEW_DATE AnnualReviewDate,
t.ANNUAL_REVIEW_STATUS AnnualReviewStatus,
t.payment_received PaymentRecieved,
t.TRAINEE_ID TraineeId,
t.IPD_SIGNUP_DATE IpdSignupDate,
t.START_DATE StartDate,
t.END_DATE EndDate,
t.LENGTH_ON_SCHEME LengthOnScheme,
t.EMPLOYEE_NUMBER EmploymentNumber,
t.SELECTED_LEVEL SelectedLevel,
t.SELECTED_LEVEL_DESCRIPTION SelectedLevelDescription,
t.ELIGIBLE_LEVEL EligibleLevel,
t.ELIGIBLE_LEVEL_DESCRIPTION EligibleLevelDescription,
sce.FORENAMES SceForenames,
sce.FORENAME SceForename,
sce.SURNAME SceSurname,
sce.mentor_name SceName,
sce.EMPLOYEE_NUMBER SceEmployeeNumber,
de.FORENAMES DeForenames,
de.FORENAME DeForename,
de.SURNAME DeSurname,
de.mentor_name DeName,
de.EMPLOYEE_NUMBER DeEmployeeNumber,
t.COMPLETED_ATTRIBUTE_LEVELS CompletedAttributeLevels,
t.ATTRIBUTE_LEVEL_COUNT AttributeLevelCount,
-- get percentage
CASE t.ATTRIBUTE_LEVEL_COUNT
WHEN 0 THEN 0
ELSE
COMPLETED_ATTRIBUTE_LEVELS / t.ATTRIBUTE_LEVEL_COUNT * 100
END percentage,
DECODE(F_ISTRAINEEGROUPMEMBER(t.ORG_REGISTRATION_ID, 'S', t.person_id),'Y','N','Y') WithoutTsaGroup,
orr.status SchemeStatus,
(select count(*) from TRAINING_GROUP_TRAINEE tgt where tgt.trainee_id = t.TRAINEE_ID) NUMBER_OF_GROUPS,
TotalCount
FROM v_trainee t
INNER JOIN org_registration orr ON t.ORG_REGISTRATION_ID = orr.id
LEFT OUTER JOIN v_mentor sce ON t.sce_id = sce.MENTOR_ID
LEFT OUTER JOIN v_mentor de ON t.de_id = de.MENTOR_ID
where t.ORG_REGISTRATION_ID = schemeid AND t.status = 'A'
and LOWER(t.trainee_name) like '%' || LOWER(searchval) || '%'
)
where rnum >= startposition and rnum <= endposition;
END;
I want to use this variable with the assigned sql:
dynamic_query rnum,
But when I execute the stored procedure I get this error:
ORA-01722: invalid number ORA-06512: at
"db.SP_TSA_TRAINEES_PAGINATION", line 46 ORA-06512: at line 13
So basically my question is can I assign a SQL to VARCHAR2 and then use it in a select statement dynamically.
You may need dynamic SQL for this. For example:
create or replace procedure testDyn(n in number, C OUT SYS_REFCURSOR) is
vDynamicPart varchar2(1000);
vSQl varchar2(1000);
begin
--
if (n = 1) then
vDynamicPart := 'count(1)';
else
vDynamicPart := 'count(null)';
end if;
--
vSQl := 'select ' || vDynamicPart || ' from dual';
open C for vSQl;
end;
If you call it
declare
n1 number;
n2 number;
C1 SYS_REFCURSOR;
C2 SYS_REFCURSOR;
begin
testDyn(1, C1);
testDyn(2, C2);
fetch C1 into n1;
fetch C2 into n2;
dbms_output.put_line('n1: ' || n1);
dbms_output.put_line('n2: ' || n2);
end;
you get:
n1: 1
n2: 0
I have an assignment asking me to rewrite this PL/SQL code I wrote for a previous assignment:
DECLARE
-- Variables used to count a, b, c, d, and f grades:
na integer := 0;
nb integer := 0;
nc integer := 0;
nd integer := 0;
nf integer := 0;
BEGIN
select count(*) into na
from gradeReport1
where grade = 'A';
select count(*) into nb
from gradeReport1
where grade = 'B';
select count(*) into nc
from gradeReport1
where grade = 'C';
select count(*) into nd
from gradeReport1
where grade = 'D';
select count(*) into nf
from gradeReport1
where grade = 'F';
if na > 0 then
DBMS_OUTPUT.PUT_LINE('There are total ' || na || ' A''s');
else
DBMS_OUTPUT.PUT_LINE('There are no As');
end if;
if nb > 0 then
DBMS_OUTPUT.PUT_LINE('There are total ' || nb || ' B''s');
else
DBMS_OUTPUT.PUT_LINE('There are no Bs');
end if;
if nc > 0 then
DBMS_OUTPUT.PUT_LINE('There are total ' || nc || ' C''s');
else
DBMS_OUTPUT.PUT_LINE('There are no Cs');
end if;
if nd > 0 then
DBMS_OUTPUT.PUT_LINE('There are total ' || nd || ' D''s');
else
DBMS_OUTPUT.PUT_LINE('There are no Ds');
end if;
if nf > 0 then
DBMS_OUTPUT.PUT_LINE('There are total ' || nf || ' F''s');
else
DBMS_OUTPUT.PUT_LINE('There are no Fs');
end if;
END;
All it does is search a table I made called gradeReport that stores studentID's and associates them with a grade. The PL/SQL counts all instances of a grade A through F. The question wants me to rewrite this solution using looping and VARRAYS. Could anyone give me a hint to help get the ball rolling for me? I've only been using PL/SQL for a few weeks and don't have much more than a basic understanding of the syntax so I'm completely lost and have no idea where to start.
Not looking for any answers here, just some ideas.
Thank You
How about starting with the doc. http://docs.oracle.com/database/122/LNPLS/plsql-control-statements.htm#LNPLS004
DECLARE
-- Need to ensure the array size will hold all the grades
TYPE grade_tab IS VARRAY(200) OF gradeReport1.grade%TYPE;
-- variable used to store the grades:
t_grades grade_tab;
-- Variables used to count a, b, c, d, and f grades:
na INTEGER;
nb INTEGER;
nc INTEGER;
nd INTEGER;
nf INTEGER;
BEGIN
-- Store the grades in an array:
SELECT grade
BULK COLLECT INTO t_grades
FROM gradeReport1
WHERE grade IN ( 'A', 'B', 'C', 'D', 'F' );
-- Loop through the grades and count how many of each:
FOR i IN 1 .. t_grades.COUNT LOOP
IF t_grades(i) = 'A' THEN na := na + 1;
ELSIF t_grades(i) = 'B' THEN nb := nb + 1;
ELSIF t_grades(i) = 'C' THEN nc := nc + 1;
ELSIF t_grades(i) = 'D' THEN nd := nd + 1;
ELSIF t_grades(i) = 'F' THEN nf := nf + 1;
END IF;
END LOOP;
-- Output grade counts
END;
/
However, a much simpler solution would be to do the counting in a single SQL query (although this doesn't meet the assessment's requirements of using a VARRAY):
DECLARE
-- Variables used to count a, b, c, d, and f grades:
na INTEGER;
nb INTEGER;
nc INTEGER;
nd INTEGER;
nf INTEGER;
BEGIN
SELECT COUNT( CASE grade WHEN 'A' THEN 1 END ),
COUNT( CASE grade WHEN 'B' THEN 1 END ),
COUNT( CASE grade WHEN 'C' THEN 1 END ),
COUNT( CASE grade WHEN 'D' THEN 1 END ),
COUNT( CASE grade WHEN 'F' THEN 1 END )
INTO na,
nb,
nc,
nd,
nf
FROM gradeReport1;
-- Output grade counts...
END;
/
Edit: as the requirement is specifically for varrays, see replies by AmmoQ and MTO. As they both point out, though, you'd be unlikely to need arrays for this type of task in practice, and even if you did, you would use a nested table or an associative array and not a varray.
You'll want a Cursor FOR loop, along the lines of
for r in (
select grade from gradereport1
)
loop
...
end loop;
In real code you'd probably make that a group by query and have SQL do the counting for you.
Then just conditionally increment the counters in the loop depending in the value of r.grade.
You can rationalise all of the if statements for reporting the totals by writing a procedure that takes a grade and a total, as the logic is the same for all of them.
procedure showgrade
( p_grade gradereport1.grade%type
, p_count integer )
is
begin
...
end showgrade;
I'll leave the details as an exercise.
Just for fun, here is another approach, using arrays and looping (but not a varray - they really are a bit useless):
declare
type gradereport_tt is table of pls_integer index by gradereport.grade%type;
gradecounts gradereport_tt;
g gradereport.grade%type;
begin
-- Initialise counts:
gradecounts('A') := 0;
gradecounts('B') := 0;
gradecounts('C') := 0;
gradecounts('D') := 0;
gradecounts('E') := 0;
gradecounts('F') := 0;
-- Count grades:
for r in (
select grade from gradereport
)
loop
gradecounts(r.grade) := gradecounts(r.grade) +1;
end loop;
-- Report counts:
g := gradecounts.first;
while g is not null loop
dbms_output.put_line(g || ': ' || gradecounts(g));
g := gradecounts.next(g);
end loop;
end;
btw there is no need to put brackets after if as in some other languages, unless the condition contains a mixture of and and or conditions that need separating.
There is also no need to write anything in uppercase. It's quite common and Steven Feuerstein does it all the time, but they had this debate in the HTML/CSS world and settled on lowercase for readability. And if you are going to have an uppercase rule, at least use it consistently. Your code example has end if; but END; not to mention Select (which I've fixed). Some people seem to be able to read code like this without it driving them nuts, but I'm afraid I'm not one of them.
set SERVEROUTPUT ON
declare
type number_array is VARRAY(5) OF integer;
total integer :=0;
i number :=1;
begin
numbers :=number_array(14,45,67,89,21);
arr_size := numbers.count;
FOR i in 1..arr_size loop
total :=total+numbers(i);
end loop;
dbms_output.put_line('total-' || total);
end;
here I want to count the number_array elements, but I can't get the correct answers. what is the problem with this?
A solution using VARRAYs could look like that:
DECLARE
type chararray IS VARRAY(6) OF CHAR(1);
type numarray IS VARRAY(6) OF INTEGER;
grades chararray;
cnt numarray;
BEGIN
select grade, count(*)
bulk collect into grades, cnt
from gradeReport1
group by grade
order by grade;
for i in 1..grades.count loop
DBMS_OUTPUT.PUT_LINE('There are total ' || cnt(i) || ' ' ||grades(i)||'s');
end loop;
END;
/
But honestly, it's pointless to use VARRAYs in that case. Just use a cursor loop:
BEGIN
for c in ( select grade, count(*) cnt
from gradeReport1
group by grade
order by grade ) loop
DBMS_OUTPUT.PUT_LINE('There are total ' || c.cnt || ' ' ||c.grade||'s');
end loop;
END;
/
Finding the missing marks (those with a count of 0) is a bit more difficult, though.
I have tried to execute code the instruction below. But somehow I cant get it working. I am new to PL/SQl. Any hint will be valuable thanks
The rank table has:
rankID Number
name Varchar2(255 BYTE)
/*
Write PL/SQL program (anonymous block) that prints out a list of all ranks (ID
and name) for all rank ID from 100 to 110. If a rank ID (xxx) does not appear
in the rank table the program should print out: NO RANK AVAILABLE for ID:
xxx
*/
--set serveroutput on
DECLARE
rank_id NUMBER;
rank_name VARCHAR2(255);
loopcount NUMBER;
BEGIN
loopcount :=100;
FOR k IN 100..110
LOOP
SELECT rankID, name
INTO rank_id, rank_name
FROM rank
WHERE rankID=loopcount;
DBMS_OUTPUT.PUT_LINE(rank_id||' '|| rank_name);
loopcount := loopcount + 1;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO RANK AVAILABLE for ID: '||rank_id);
END;
/
Below is what I am getting. Its not working the way it should
Server output:
100 Chefpilot
NO RANK AVAILABLE for ID: 100
DECLARE executed successfully
Execution time: 0.26s
No real need for a loop in this case, you can do this with an outer join, a case statement and a numbers table:
WITH CTE (RankId) AS (
SELECT 100 RankId
FROM DUAL
UNION ALL
SELECT RankId + 1
FROM CTE
WHERE RankId < 110
)
SELECT t.RankId, COALESCE(r.Name, 'Does not exist') Name,
CASE
WHEN r.RankId IS NULL THEN 'No rank available for: ' || t.RankId
ELSE r.RankId || ' ' || r.Name
END Description
FROM CTE t
LEFT JOIN rank r ON t.RankId = r.RankId
ORDER BY t.RankId
SQL Fiddle Demo
#sgeddes's approach is better, but to explain what you are seeing, if you did want to use your mechamism then you'd need to catch the exception in an inner block. At the moment the exception handler is outside the loop, so the first error you see terminates the loop. With an inner block:
DECLARE
rank_id NUMBER;
rank_name VARCHAR2(255);
BEGIN
FOR loopID IN 100..110
LOOP
BEGIN -- inner block
SELECT rankID, name
INTO rank_id, rank_name
FROM rank
WHERE rankID=loopID;
DBMS_OUTPUT.PUT_LINE(rank_id||' '|| rank_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO RANK AVAILABLE for ID: '||loopID);
END; -- inner block
END LOOP;
END;
/
Now if the ID doesn't exist the exception is caught, the message is printed, and the inner block exits; which means the loop continues at the next iteration. (I've also removed the extra loopcount and consistently used a loopID for the for and both references).
here is my serial table.it has more than 1000 records.its with start number and end number.but between numbers not exist.
i need to add all number [start/between & end numbers] records in another temp table number by number
like below
EXIST TABLE
select concat(CARD_BULK_CODE,start_serial) startserial,concat(CARD_BULK_CODE,end_serial) endserial
from TSR_BULK_CARD_SERIALS
---------------------------
STARTSERIAL ENDSERIAL |
---------------------------
18126944 18126946 |
18141101 18141122 |
15150722 15150729 |
19069303 19069317 |
---------------------------
REQUIRED TABLE
-----------
SERIAL_NO |
-----------
18126944
18126945
18141101
18141102
....
-----------
seem its need pl-sql to implement this.
please help me to sort out this issue
I tried with below query with the help of dual.
but its very slow and not yet got results :-) running more than 1 Hour
select distinct concat(t.CARD_BULK_CODE,t.START_SERIAL)+level-1 SERIAL
from TSR_BULK_CARD_SERIALS t, dual
connect by level-1<=(concat(t.CARD_BULK_CODE,t.END_SERIAL ))-concat(t.CARD_BULK_CODE,t.START_SERIAL)
order by 1
EDIT :
Dear Alen & Dba.i tried with your ones and below error occured.
DECLARE
l_st NUMBER;
l_en NUMBER;
BEGIN
FOR rec IN (select concat(card_bulk_code, start_serial) startserial,concat(card_bulk_code, end_serial) endserial from tsr_bulk_card_serials)
LOOP
l_st := rec.startserial;
l_en := rec.endserial;
FOR rec1 IN l_st..l_en
LOOP
INSERT INTO temp(serial_no) values(rec1);
END LOOP;
END LOOP;
COMMIT;
END;
Error at line 1
ORA-01426: numeric overflow
ORA-06512: at line 9
Script Terminated on line 1.
One way to do it without resorting to plsql
WITH ranges AS
(
SELECT CONCAT(CARD_BULK_CODE, start_serial) startserial,
CONCAT(CARD_BULK_CODE, end_serial) endserial
FROM TSR_BULK_CARD_SERIALS
),
numbers(n) AS (
SELECT 0 n
FROM dual
UNION ALL
SELECT n + 1
FROM numbers
WHERE n <=
(
SELECT MAX(endserial - startserial)
FROM ranges
)
)
SELECT t.startserial + n.n SERIAL_NO
FROM ranges t JOIN numbers n
ON n.n <= t.endserial - t.startserial
ORDER BY SERIAL_NO
Here is SQLFiddle demo
Just write some PL/SQL - iterate through your table and insert rows in the temp table.
declare
l_start number;
l_end number;
begin
for r_rec in (select to_number(concat(card_bulk_code, start_serial)) startserial
, to_number(concat(card_bulk_code, end_serial)) endserial
from tsr_bulk_card_serials )
loop
l_start := r_rec.startserial;
l_end := r_rec.endserial;
for l_i in l_start..l_end loop
insert into your_temp_table;
end loop;
end loop;
end;
Try like this,
WITH t(ST, EN) AS
(
SELECT 18126944, 18126946 FROM dual
UNION
SELECT 18141101, 18141122 FROM dual
UNION
SELECT 15150722, 15150729 FROM dual
UNION
SELECT 19069303 , 19069317 FROM dual
)
SELECT DISTINCT st + LEVEL -1
FROM t
CONNECT BY LEVEL <= (SELECT en - st + 1 FROM DUAL)
ORDER BY 1;
/
Try something like this for PL/SQL,
DECLARE
l_st NUMBER;
l_en NUMBER;
BEGIN
FOR rec IN (SELECT * FROM t)
LOOP
l_st := rec.st;
l_en := rec.en;
FOR rec1 IN l_st..l_en
LOOP
INSERT INTO <your_tab>;
END LOOP;
END LOOP;
COMMIT;
END;
DECLARE
l_st NUMBER (20);
l_en NUMBER (20);
testnum NUMBER (4);
BEGIN
FOR rec IN (SELECT CONCAT (card_bulk_code, start_serial) startserial,CONCAT (card_bulk_code, end_serial) endserial FROM tsr_bulk_card_serials)
LOOP
l_st := TO_NUMBER (rec.startserial);
l_en := TO_NUMBER (rec.endserial);
testnum := l_en - l_st;
DBMS_OUTPUT.put_line (l_st);
DBMS_OUTPUT.put_line (l_en);
IF l_st < l_en
THEN
FOR rec1 IN 0 .. testnum
LOOP
l_st := l_st + 1;
INSERT INTO temp(serial_no) VALUES (l_st);
END LOOP;
END IF;
END LOOP;
COMMIT;
END;
above code helped me to sorted my issue
thanks all :-)
I give the SQL few inputs and I need to get all the ID's and their count that doesn't satisfy the required criteria.
I would like to know if there are there any alternatives to using cursor.
DECLARE
v_count INTEGER;
v_output VARCHAR2 (1000);
pc table1%ROWTYPE;
unmarked_ids EXCEPTION;
dynamic_sql VARCHAR (5000);
cur SYS_REFCURSOR;
id pp.id%TYPE;
pos INTEGER;
BEGIN
v_count := 0;
SELECT *
INTO pc
FROM table1
WHERE id = '&ID';
DBMS_OUTPUT.ENABLE;
dynamic_sql :=
'SELECT ID from pp
WHERE ( TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:a, ''yyyy/mm/dd''))
AND aid IN (SELECT aid FROM ppd WHERE TO_CHAR(cdate, ''yyyy/mm/dd'') =
TO_CHAR (:b, ''yyyy/mm/dd'')
AND cid = :c )
AND cid <> :d';
OPEN cur FOR dynamic_sql USING pc.cdate, pc.cdate, pc.id, pc.id;
LOOP
FETCH cur INTO id;
EXIT WHEN cur%NOTFOUND;
v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE (' Id:' || id);
END LOOP;
CLOSE cur;
IF (v_count > 0)
THEN
DBMS_OUTPUT.PUT_LINE ( 'Count: ' || v_count || ' SQL: ' || dynamic_sql);
RAISE unmarked_ids;
END IF;
DBMS_OUTPUT.PUT_LINE('SQL ended successfully');
EXCEPTION
WHEN unmarked_ids
THEN
DBMS_OUTPUT.put_line (
'Found ID's that not marked with the current id.');
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'No data found in table1 with the current id ' || '&ID');
END;
There are bind variables in the query. One of them is date, there are three more.
The count and ID's are required to be shown which will later be reported.
You could store the rowid in a temporary table along with an index value (0...n) and then use a while loop to go through the index values and join to the real table using the rowid.