Adapt function to procedure - sql

I have the below function and I would like to turn it into a procedure. What would be the changes I need to accomplish it? I would like to turn it into a procedure because it's kind of a one purpose use function, and I would prefer to have it inside my main package along with my other procedures.
I would like to, instead of returning the table, creating it inside the procedure itself.
CREATE OR REPLACE FUNCTION pick_values RETURN t1_prueba_table
PIPELINED
IS
TYPE t2_type IS
TABLE OF t2%rowtype;
t2_data t2_type;
v_pc t1.pc%TYPE;
BEGIN
-- https://stackoverflow.com/a/67516191/1509264
-- License: CC BY-SA 4.0
FOR cur IN (
SELECT *
FROM t1
ORDER BY pc, r
) LOOP
IF v_pc IS NULL OR v_pc <> cur.pc THEN
v_pc := cur.pc;
SELECT *
BULK COLLECT INTO t2_data
FROM t2
WHERE pc = cur.pc;
END IF;
DECLARE
a_freqs int_list := int_list();
cum_freq INT := 0;
taken string_list := split_string(cur.an, ', ');
idx INT;
c t2.a%TYPE;
BEGIN
a_freqs.extend(t2_data.count);
FOR i IN 1..t2_data.count LOOP
IF t2_data(i).a = cur.ao
AND t2_data(i).c > 0
THEN
-- If there is an "ao" value and it has capacity then assign it to "c"
c := t2_data(i).a;
-- Decrement the appropriate "t2_data" row to show it has been used.
t2_data(i).c := t2_data(i).c - 1;
-- Set the "cum_freq" to 0 so the loop where values are randomly assigned is skipped.
cum_freq := 0;
-- Exit the loop
EXIT;
ELSIF (
t2_data(i).a = cur.ay
AND t2_data(i).c > 0
) OR (
cur.ay IS NULL
AND t2_data(i).a NOT MEMBER OF taken
AND t2_data(i).c > 0
)
THEN
a_freqs(i) := cum_freq + t2_data(i).c;
cum_freq := cum_freq + t2_data(i).c;
ELSE
a_freqs(i) := cum_freq;
END IF;
END LOOP;
IF cum_freq > 0 THEN
idx := floor(dbms_random.value(0, cum_freq));
FOR i IN 1..t2_data.count LOOP
IF idx < a_freqs(i) THEN
c := t2_data(i).a;
t2_data(i).c := t2_data(i).c - 1;
EXIT;
END IF;
END LOOP;
END IF;
PIPE ROW (
t1_prueba_data(cur.pc, cur.vk, cur.ay, cur.ao, cur.an, cur.r, c)
);
END;
END LOOP;
END;
Kindly let me know if any additional information needed.

A package can contain both procedures and functions.
There is no need to convert this from a function to a procedure to include it in a package.
eg
create or replace package test AS
PROCEDURE test_procedure (in_test in varchar2(100));
FUNCTION assessment_newid_f RETURN assessments.assessment_id%TYPE;
END;
create or replace package body test AS
PROCEDURE test_procedure (in_test in varchar2(100)) IS
BEGIN
...
END;
FUNCTION assessment_newid_f RETURN assessments.assessment_id%TYPE IS
BEGIN
...
RETURN ...;
END;
END;

Related

Function with table parameters Oracle

I have the below function. I would like to make it parametrisable. I would want to give as input parameters table_t5 and dunnv3_t6. Would this be possible? I know how to define functions with strings, numbers... as parameters but I'm struggling to pass tables as input parameters.
CREATE OR REPLACE FUNCTION dunnv3_ec_assign RETURN t5_table
PIPELINED
IS
TYPE t6_type IS
TABLE OF dunnv3_t6%rowtype;
t6_data t6_type;
v_cc table_t5.campaign_code%TYPE;
BEGIN
-- https://stackoverflow.com/a/67398434/1509264
-- License: CC BY-SA 4.0
FOR cur IN (
logic which orders the input table for cursor processing
) LOOP
IF v_cc IS NULL OR v_cc <> cur.cc THEN
v_cc := cur.cc;
SELECT
*
BULK COLLECT
INTO t6_data
FROM
dunnv3_t6
WHERE
cc = cur.cc;
END IF;
DECLARE
a_freqs int_list := int_list();
cum_freq INT := 0;
taken string_list := split_string(cur.an, ', ');
idx INT;
c dunnv3_t6.a%TYPE;
BEGIN
a_freqs.extend(t6_data.count);
FOR i IN 1..t6_data.count LOOP IF ( t6_data(i).a = cur.ay AND t6_data(i).c > 0 ) OR ( cur.ay IS NULL AND t6_data(i).a
NOT MEMBER OF taken AND t6_data(i).c > 0 ) THEN
a_freqs(i) := cum_freq + t6_data(i).c;
cum_freq := cum_freq + t6_data(i).c;
ELSE
a_freqs(i) := cum_freq;
END IF;
END LOOP;
IF cum_freq > 0 THEN
idx := floor(dbms_random.value(0, cum_freq));
FOR i IN 1..t6_data.count LOOP IF idx < a_freqs(i) THEN
c := t6_data(i).a;
t6_data(i).c := t6_data(i).c - 1;
EXIT;
END IF;
END LOOP;
END IF;
PIPE ROW ( t5_data(cur.vk, cur.ay, cur.an, cur.cc, cur.r,
c) );
END;
END LOOP;
END;
CREATE TYPE t5_data AS OBJECT (
vk NVARCHAR2(12),
ay CHAR(10),
an VARCHAR2(4000),
cc VARCHAR2(5),
r NUMBER,
c CHAR(10)
);
CREATE TYPE t5_table IS
TABLE OF t5_data;
Oracle version 12.1. Kindly let me know if additional info required.
EDIT, I would also need the 'logic which logic which orders the input table for cursor processing to be passed as a parameter.

PLS-00103 Encountered the symbol "END"

I'm running into the issue PL-00103: Encountered the symbol "END" on the second to last line of the following procedure. The purpose of the procedure is to see if a previous version of an email exists when a new one is sent... and expire the old email. (emails are by default set to a far away expiration date when created so I check to see if the expiration date is further than the current date).
PROCEDURE EXPIRE_STUFF_PRC
(
PI_EMAIL_NBR_STR IN VARCHAR2,
PO_SUCCESS_FLG OUT VARCHAR2,
PO_OUT_MSG OUT VARCHAR2
) AS
L_SUCCESS VARCHAR2(1) := 'N';
L_EMAIL_ID NUMBER;
L_PREV_EMAIL_VER_ID NUMBER := 0;
L_PREV_EMAIL_EXP_DT DATE;
BEGIN
BEGIN
SELECT
ITEM.EMAIL_ID
INTO L_EMAIL_ID
FROM HR_EMAIL ITEM
WHERE ITEM.EMAIL_NBR_STR = PI_EMAIL_NBR_STR;
END;
BEGIN
SELECT
VER_ID.EMAIL_VER_ID
INTO L_PREV_EMAIL_VER_ID
FROM (
SELECT
EMAIL_VER_ID
FROM HR_EMAIL_VER
WHERE EMAIL_ID = L_EMAIL_ID
ORDER BY EMAIL_VER_ID DESC
) VER_ID
WHERE ROWNUM = 2;
EXCEPTION
WHEN NO_DATA_FOUND
THEN PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'LESS THAN 2 VERSIONS';
END;
END;
BEGIN
IF (L_PREV_EMAIL_VER_ID > 0) THEN
SELECT
VER.EXP_DT
INTO L_PREV_EMAIL_EXP_DT
FROM HR_EMAIL_VER VER
WHERE VER.EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
IF (L_PREV_EMAIL_EXP_DT > SYSDATE) THEN
UPDATE HR_EMAIL_VER
SET EXP_DT = SYSDATE
WHERE EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
END IF;
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'SUCCESS';
END IF;
END;
END;
END EXPIRE_STUFF_PRC;
I've tried to move around ENDs and BEGINs to no avail...
I've changed the name of stuff due to NDA so if there is any confusion I'll be happy to clarify as I might have missed something.
Thank you in advance for any help!
You have used unnecessary BEGIN/END in your code. There could be a necessity if you want to handle exceptions in a particular section. The best way to format and check for syntax is to use a nice code editor.
I have removed all the unwanted BEGIN/END and this should compile fine:
CREATE OR REPLACE PROCEDURE expire_stuff_prc (
pi_email_nbr_str IN VARCHAR2,
po_success_flg OUT VARCHAR2,
po_out_msg OUT VARCHAR2
) AS
l_success VARCHAR2(1) := 'N';
l_email_id NUMBER;
l_prev_email_ver_id NUMBER := 0;
l_prev_email_exp_dt DATE;
BEGIN
SELECT
item.email_id
INTO l_email_id
FROM
hr_email item
WHERE
item.email_nbr_str = pi_email_nbr_str;
BEGIN
SELECT
ver_id.email_ver_id
INTO l_prev_email_ver_id
FROM
(
SELECT
email_ver_id
FROM
hr_email_ver
WHERE
email_id = l_email_id
ORDER BY
email_ver_id DESC
) ver_id
WHERE
ROWNUM = 2;
EXCEPTION
WHEN no_data_found THEN
po_success_flg := 'Y';
po_out_msg := 'LESS THAN 2 VERSIONS';
END;
IF ( l_prev_email_ver_id > 0 ) THEN
SELECT
ver.exp_dt
INTO l_prev_email_exp_dt
FROM
hr_email_ver ver
WHERE
ver.email_ver_id = l_prev_email_ver_id;
IF ( l_prev_email_exp_dt > sysdate ) THEN
UPDATE hr_email_ver
SET
exp_dt = sysdate
WHERE
email_ver_id = l_prev_email_ver_id;
END IF;
po_success_flg := 'Y';
po_out_msg := 'SUCCESS';
END IF;
END expire_stuff_prc;
/
Ideal way to write a stored procedure is to handle all exception for each of the block/statement. You have one additional END that has to be removed, additionally i have added messages to be returned when first and last block goes into any exception.
Block is in sense logically grouped DML operation, it can be just a single select or group of DML operation.Decision to be taken based on the business logic.
PROCEDURE EXPIRE_STUFF_PRC
(
PI_EMAIL_NBR_STR IN VARCHAR2,
PO_SUCCESS_FLG OUT VARCHAR2,
PO_OUT_MSG OUT VARCHAR2
) AS
L_SUCCESS VARCHAR2(1) := 'N';
L_EMAIL_ID NUMBER;
L_PREV_EMAIL_VER_ID NUMBER := 0;
L_PREV_EMAIL_EXP_DT DATE;
BEGIN
BEGIN
SELECT
ITEM.EMAIL_ID
INTO L_EMAIL_ID
FROM HR_EMAIL ITEM
WHERE ITEM.EMAIL_NBR_STR = PI_EMAIL_NBR_STR;
EXCEPTION WHEN OTHERS THEN
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'COULD NOT FETCH EMAIL_ID';
END;
BEGIN
SELECT
VER_ID.EMAIL_VER_ID
INTO L_PREV_EMAIL_VER_ID
FROM (
SELECT
EMAIL_VER_ID
FROM HR_EMAIL_VER
WHERE EMAIL_ID = L_EMAIL_ID
ORDER BY EMAIL_VER_ID DESC
) VER_ID
WHERE ROWNUM = 2;
EXCEPTION
WHEN NO_DATA_FOUND
THEN PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'LESS THAN 2 VERSIONS';
END;
BEGIN
IF (L_PREV_EMAIL_VER_ID > 0) THEN
SELECT
VER.EXP_DT
INTO L_PREV_EMAIL_EXP_DT
FROM HR_EMAIL_VER VER
WHERE VER.EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
IF (L_PREV_EMAIL_EXP_DT > SYSDATE) THEN
UPDATE HR_EMAIL_VER
SET EXP_DT = SYSDATE
WHERE EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
END IF;
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'SUCCESS';
END IF;
EXCEPTION
WHEN OTHERS THEN
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'UNABLE TO UPDATE HR_EMAIL_VER';
END;
END EXPIRE_STUFF_PRC;

Generate dynamic SQL query with multiple filter option(from application)added in single CLOB - Oracle

There is application in which filter option includes start date, end date, postcode, etc where user can select multiple option from single filter. Ex: User can select 5 different start date, end date and 3 different postcode or can select 1 start date, end date and no postcode. There are 7 other filters and each filter user can select multiple options. (Consider E-Commerce website like Amazon. If you want to buy mobile, you use filter for camera range like 16MP,32MP,48MP and company like 'Samsung','Motorola', 'Nokia' and similarly for processor and screen size as well. So as a developer you want to store all the value in CLOB and give the result)
Input will come something like
<date>
<start_date>01/01/2019</start_date>
<end_date>31/01/2019</end_date>
<start_date>01/03/2019</start_date>
<end_date>31/03/2019</end_date>
<start_date>01/05/2019</start_date>
<end_date>31/05/2019</end_date>
</date>
<pc>
<postcode>56012</postcode>
<postcode>56000</postcode>
<postcode>56234</postcode>
</pc>
Now my query should look something like
select col1,col2,col3 from table_name where between start_date and end_date and between start_date and end_date... and postcode like '56012' and postcode like '56000'
Result set retruned should again be sent in clob.
Is there any way out to solve this problem?
create or replace procedure get_data(p_filter IN clob, p_result clob)
is
v_query clob;
V_condition clob;
v_lp_cnt integer;
v_result clob;
v_where_clause clob;
begin
--Considering output will be returned in XML
v_query := 'SELECT XMLELEMENT (
"data", XMLAGG
(XMLELEMENT
(
"whole_data",
XMLELEMENT ("final_date", final_date),
......... from table_name where col2='xyz'';
--Considering that filter values will be less than 1000
--date
V_condition := NULL;
v_lp_cnt := 0;
FOR crec IN(SELECT t.start_date, t.end_date
FROM XMLTABLE('/Filter/final_date/Date'
PASSING xmltype(p_filter)
COLUMNS
start_date VARCHAR2(240) PATH 'Start_Date',
end_date VARCHAR2(240) PATH 'End_Date')t
WHERE 1 = 1
)
loop
v_lp_cnt := v_lp_cnt +1;
IF v_lp_cnt =1
THEN
v_condition := ' AND (ext.final_date between to_date('''|| crec.start_date ||''',''dd/mm/yyyy'') and to_date('''|| crec.end_date ||''',''dd/mm/yyyy'')';
v_where_clause := v_where_clause||v_condition;
v_condition:= null;
ELSIF (v_lp_cnt >1 and v_lp_cnt <1000)
THEN
v_condition := ' OR ext.final_date between to_date('''|| crec.start_date ||''',''dd/mm/yyyy'') and to_date('''|| crec.end_date ||''',''dd/mm/yyyy'')';
v_where_clause := v_where_clause||v_condition;
end if;
end loop;
IF v_lp_cnt>0
THEN
v_where_clause := v_where_clause|| ')';
END IF;
--postcode
v_condition := NULL;
v_lp_cnt := 0;
FOR crec IN(SELECT (t.postcode) postcode
FROM XMLTABLE('/Filter/pc/postcode'
PASSING xmltype(p_filter)
COLUMNS postcode VARCHAR2(30)PATH '/postcode')t
WHERE 1 = 1
)
loop
v_lp_cnt := v_lp_cnt + 1;
IF v_lp_cnt = 1 THEN
v_condition := ' AND (postcode in ('''|| crec.postcode ||'''';
v_where_clause := v_where_clause||v_condition;
v_condition := NULL;
ELSE
v_condition := v_condition||','||''''|| crec.postcode ||'''';
v_where_clause := v_where_clause||v_condition;
v_condition := NULL;
END IF;
END LOOP;
IF v_lp_cnt >0
THEN
v_where_clause := v_where_clause||v_condition||'))';
end if;
v_query := v_query || v_where_clause;
execute immediate v_query into v_result;
p_result := v_result;
end;

Create a NZPLSQL to find min(date) and a max(date) for a group of fields that serve as a key

I would like to know how I can execute a select from a procedure stored in Netezza.
I currently have the procedure under construction and I read that the raise notice serves to print on screen, however I do not know how (or if you can print a table in sql) just as if you were doing a query in traditional sql.
What the query is trying to do is that for a record,
COUNT (*) AS N_REPETITIONS,
CDS.CASO_PACIENTE_FK,
CDS.RESIVALITY_SPECIALITY_COD,
CDS.CASO_NIVEL_ATENCION_TIPO,
CDS.CASO_TIPO_PRESTACION_FK,
CDS.DIVING_DATE_DAY,
CDS.SALID_DATE_DAY
and that it gives me MIN(CDS.DERIVACION_FECHA_HORA) and MAX(CDS.SALIDA_FECHA_HORA) based on a key that are the fields.
If I have dates between MIN(CDS.DERIVACION_FECHA_HORA) and MAX(CDS.SALIDA_FECHA_HORA) for a CDS.CASO_PACIENTE_FK, i want that register added to number of register for each CDS.CASO_PACIENTE_FK
Here the code:
CREATE OR REPLACE PROCEDURE SP_ANALISIS_DUPLICADOS()
RETURNS REFTABLE(NETEZZA_PROD_LISTA_ESPERA_NOGES.LLAVE_CASOS_DUPLICADOS)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
num_args INTEGER;
I am just starting to work with Netezza.
Thank you in advance to whom you answer.
This is the code:
CREATE OR REPLACE PROCEDURE SP_ANALISIS_DUPLICADOS()
RETURNS REFTABLE(NETEZZA_PROD_LISTA_ESPERA_NOGES.LLAVE_CASOS_DUPLICADOS)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
num_args INTEGER;
typ oid;
idx INTEGER;
N_REPETICIONES NUMERIC(19);
CASO_PACIENTE_FK NUMERIC(19);
DERIVACION_ESPECIALIDAD_COD VARCHAR(255);
CASO_NIVEL_ATENCION_TIPO NUMERIC(19);
CASO_TIPO_PRESTACION_FK NUMERIC(19);
DERIVACION_FECHA_HORA TIMESTAMP;
SALIDA_FECHA_HORA TIMESTAMP;
--CURSOR FECHA_HORA_DERIVACION_MIN;
--CURSOR FECHA_HORA_SALIDA_MAX;
CURSOR CASO_PACIENTE_FK;
CURSOR DERIVACION_ESPECIALIDAD_COD;
CURSOR CASO_NIVEL_ATENCION_TIPO;
CURSOR CASO_TIPO_PRESTACION_FK;
--L_CONDITIONS VARCHAR(1000);
--Duplicados CNE MIN
BEGIN
num_args := PROC_ARGUMENT_TYPES.count;
FOR CASO_PACIENTE_FK IN
num_args := CASO_PACIENTE_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for i IN 0
CASO_PACIENTE_FK.count - 1 LOOP
typ := CASO_PACIENTE_FK(i);
idx := i+1;
FOR DERIVACION_ESPECIALIDAD_COD IN
num_args := DERIVACION_ESPECIALIDAD_COD.count;
for j IN 0
DERIVACION_ESPECIALIDAD_COD.count - 1 LOOP
typ := DERIVACION_ESPECIALIDAD_COD(j);
idx := j+1;
FOR CASO_NIVEL_ATENCION_TIPO IN
num_args := CASO_PACIENTE_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for k IN 0
CASO_NIVEL_ATENCION_TIPO.count - 1 LOOP
typ := CASO_NIVEL_ATENCION_TIPO(k);
idx := k+1;
FOR CASO_TIPO_PRESTACION_FK IN
num_args := CASO_TIPO_PRESTACION_FK.count;
--RAISE NOTICE ’Number of arguments: %’, num_args;
for a IN 0
CASO_TIPO_PRESTACION_FK.count - 1 LOOP
typ := CASO_TIPO_PRESTACION_FK(a);
idx := a+1;
--RAISE NOTICE ’argument $% is type % and has the value ’’%’’’,
--idx, typ, $idx;
F FLAG = 1 THEN
IF Fecha_Entrada = SELECT COUNT(*) AS N_REPETICIONES, MIN(CDS.DERIVACION_FECHA_HORA) AS FECHA_HORA_DERIVACION_MIN
FROM NETEZZA_PROD_SIGTE_DIARIO.SIG_CASO_DERIVACION_SALIDA CDS
WHERE (CDS.CASO_TIPO_PRESTACION_FK=1
OR CDS.CASO_TIPO_PRESTACION_FK=2)
--AND CDS.DERIVACION_FECHA_HORA >= CDS.DERIVACION_FECHA_HORA
GROUP BY CDS.CASO_PACIENTE_FK, CDS.DERIVACION_ESPECIALIDAD_COD, /*CDS.DERIVACION_ESTABLECIMIENTO_COD*/
CDS.CASO_NIVEL_ATENCION_TIPO, /*CDS.DERIVACION_FECHA_HORA,*/ CDS.CASO_TIPO_PRESTACION_FK, CDS.DERIVACION_FECHA_HORA,
CDS.SALIDA_FECHA_HORA
HAVING COUNT(*)>1
ORDER BY N_REPETICIONES, CDS.CASO_PACIENTE_FK, CDS.DERIVACION_FECHA_HORA, CDS.SALIDA_FECHA_HORA DESC
THEN Fecha_Entrada = 'TRUE';
ELSE FLAG = 0 THEN
Fecha_Entrada = 'FALSE'
F FLAG = 1 THEN
IF Fecha_Salida = SELECT COUNT(*) AS N_REPETICIONES, MAX(CDS.SALIDA_FECHA_HORA) AS FECHA_HORA_DERIVACION_MIN
FROM NETEZZA_PROD_SIGTE_DIARIO.SIG_CASO_DERIVACION_SALIDA CDS
WHERE (CDS.CASO_TIPO_PRESTACION_FK=1
OR CDS.CASO_TIPO_PRESTACION_FK=2)
--AND CDS.DERIVACION_FECHA_HORA >= CDS.DERIVACION_FECHA_HORA
GROUP BY CDS.CASO_PACIENTE_FK, CDS.DERIVACION_ESPECIALIDAD_COD, /*CDS.DERIVACION_ESTABLECIMIENTO_COD*/
CDS.CASO_NIVEL_ATENCION_TIPO, /*CDS.DERIVACION_FECHA_HORA,*/ CDS.CASO_TIPO_PRESTACION_FK, CDS.DERIVACION_FECHA_HORA,
CDS.SALIDA_FECHA_HORA
HAVING COUNT(*)>1
ORDER BY N_REPETICIONES, CDS.CASO_PACIENTE_FK, CDS.DERIVACION_FECHA_HORA, CDS.SALIDA_FECHA_HORA DESC
THEN Fecha_Salida = 'TRUE';
ELSE FLAG = 0 THEN
Fecha_Salida = 'FALSE'
END LOOP;
END LOOP;
END LOOP;
END LOOP;
RETURN REFTABLE;
RAISE NOTICE 'Hello, %', MYNAME; --Right Here must go the Println (Select field1, field2, etc.....)
--END;
--COMMIT;
END;
END_PROC;

Any alternatives to using cursor in SQL procedure in Oracle 10g?

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.