Select into a variable with case statement in a for loop - sql

The foo variable should be filled with a select case within a for loop and then put out. I used a goto end_loop reference inside an exception, so the loop can continue.
Before I put the exception, I had an ORA-01403 error. Now I have an ORA-01422 error. The other selects without the case statement worked fine.
declare
foo varchar2(2000);
BEGIN
FOR rec IN (SELECT something FROM somewhere)
LOOP
BEGIN
Select case when attribute = 'something' then '1' end into foo from somewhere where some_condition;
DBMS_OUTPUT.put_line( 'Something' || foo);
EXCEPTION
WHEN NO_DATA_FOUND THEN
foo := NULL;
goto end_loop;
END;
<<end_loop>>
null;
END LOOP;
END;
Edit
More detailed
declare
opdatum varchar2(2000);
opdiagnose varchar2(2000);
d_op varchar2(2000);
some_variable varchar2(2000);
BEGIN
FOR rec IN (SELECT p.name, p.vorname, p.geburtsdatum, a.kis_id, kg.kg_id FROM kg_eintraege kg
INNER JOIN aufenthalte a
ON kg.patient_nr = a.patient_nr
and kg.fall_nr = a.fall_nr
INNER JOIN personen p
ON a.patient_nr = p.pat_nr
WHERE kg.kgtitel_nr = xxxxxxa
and a.kis_id = xxxxxxb)
LOOP
BEGIN
Select kurztext into opdatum from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxc;
Select text into opdiagnose from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxd;
Select text into d_op from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxe;
Select case when kurztext = 'Something' then '1' end into some_variable from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxf;
DBMS_OUTPUT.put_line(rec.name || ' ' || rec.vorname || ' ' || TO_CHAR(rec.geburtsdatum, 'DD.MM.YYYY')
|| ' ' || rec.kis_id || ' ' || opdatum|| ' ' || opdiagnose ||
' ' || d_op || ' ' || some_variable
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
some_variable := NULL;
goto end_loop;
END;
<<end_loop>>
null;
END LOOP;
END;
Update
The case statement seems to be alright. The problem is that some rows in the select are null.
Update2
No exception needed.
Solution:
select nvl((select case when kurztext = 'Something' then '1' end from kg_eintraege where kontext = rec.kg_id and kgtitel_nr = xxxxxxf and kurztext = 'Something'), 'NOT_FOUND') into some_variable from dual
Thanks to NikNik for the help.

You problem is not the CASE but your WHERE condition witch is retourning more than 1 record or 0 record found.
For more details look here.
In the second case you can do this:
select nvl( (your_case), 'NOT_FOUND' ) into foo from dual;

Related

How can i turn this pl/sql into a procedure

I had to write this query for an assignement. So we have a database and we are pulling information from it, this is going to work with some back end c# eventually. Is there anything i can do , knowing im going to reuse this, in order to make it better and more adaptable when the day comes when i have to connect it all.
set serveroutput on
DECLARE
LV_DATE HVK_RESERVATION.RESERVATION_START_DATE%TYPE;
LV_SERV VARCHAR(100);
CURSOR LCUR_RES IS
SELECT *
FROM HVK_RESERVATION R
INNER JOIN HVK_PET_RESERVATION PR
ON R.RESERVATION_NUMBER = PR.RES_RESERVATION_NUMBER
INNER JOIN HVK_PET P
ON P.PET_NUMBER = PR.PET_PET_NUMBER
INNER JOIN HVK_OWNER OW
ON OW.OWNER_NUMBER = P.OWN_OWNER_NUMBER
WHERE R.RESERVATION_START_DATE < LV_DATE
AND R.RESERVATION_END_DATE > LV_DATE;
CURSOR LCUR_SERVICE(PET_RES_NUM NUMBER) IS
SELECT *
FROM HVK_SERVICE S
INNER JOIN HVK_PET_RESERVATION_SERVICE PRS
ON PRS.SERV_SERVICE_NUMBER = S.SERVICE_NUMBER
AND PRS.PR_PET_RES_NUMBER = PET_RES_NUM;
BEGIN
LV_DATE := TO_DATE('&logdate', 'yy-mm-dd');
DBMS_OUTPUT.PUT_LINE('Kennel log for ' || '' || LV_DATE);
DBMS_OUTPUT.PUT_LINE('-------------------------------');
FOR I IN LCUR_RES LOOP
DBMS_OUTPUT.PUT_LINE('Run:' || '' || I.RUN_RUN_NUMBER || ' ' ||
'Pet: ' || '' || I.PET_NAME || ' ' ||
I.OWNER_LAST_NAME || ' Pet Reservation: ' || '' ||
I.PET_RES_NUMBER);
DBMS_OUTPUT.PUT_LINE('Reservation start/end ' || ' ' ||
I.RESERVATION_START_DATE || ' ' ||
I.RESERVATION_END_DATE);
DBMS_OUTPUT.PUT('Services : ');
FOR X IN LCUR_SERVICE(I.PET_RES_NUMBER) LOOP
DBMS_OUTPUT.PUT(X.SERVICE_DESCRIPTION || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
FOR LREC_LOG IN (SELECT *
FROM HVK_KENNEL_LOG KL
WHERE KL.PR_PET_RES_NUMBER = I.PET_RES_NUMBER
) LOOP
DBMS_OUTPUT.PUT_LINE('Notes: ' || '' ||
LREC_LOG.KENNEL_LOG_SEQUENCE_NUMBER || ' ' ||
'Log Note: ' || '' || LREC_LOG.KENNEL_LOG_NOTES);
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
END;
It it supposed to output the run number , reservation number , pet name , and any relate notes.
you can replace DECLARE with CREATE OR REPLACE PROCEDURE my_proc(in_logdate in date) IS.
in that case my_proc will be the name of your procedure.
you should also use a parameter instead of &logdate
so e.g. parameter name in_logdate of type date
...
LV_DATE := in_logdate;
...

ORA-01722: invalid number in execute immediate

I am running the following script in SQL Developer but getting the below error -
ORA-01722: invalid number
ORA-06512: at line 85
The data passed to this query is coming from a different table.
DATA BEING PASSED -
BAN - 945170744, ACTV_BILL_SEQ_NO- 12 , SUBSCRIBER_NO - 1234567891, DISCOUNT_CD - NULL, PRIOD_CVRG_ND_DATE - 04-JAN-20,
Note - Ban is defined as NUMBER(9) in both the tables.
SCRIPT -
SET SERVEROUTPUT ON
DECLARE
V_HIERARCHY_ID NUMBER(10);
V_NODE_CYCLE NUMBER(2);
V_BILL_CYCLE NUMBER(2);
V_DISCOUNT_CD CHAR(9);
V_EXP_DATE DATE;
V_COUNT NUMBER(3);
v_val_Done_by varchar2(25) ;
v_ban NUMBER(9);
v_comments varchar2(20);
v_success varchar2(10) :='SUCCESS';
v_yesnoind varchar2(1) :='Y';
v_comments_1 varchar2(30) :='DISCOUNT EXPIRED';
v_comments_2 varchar2(30) :='DISCOUNT NOT FOUND';
v_issue_Desc varchar2(50) :='NEW RECORD MISSING';
BEGIN
DBMS_OUTPUT.put_line ('BAN: '|| :1 || ' ACTV_BILL_SEQ_NO : ' || :2 || ' SUBSCRIBER: '|| :3 ||
'COLUMN_NAME : ' || :4|| ' COLUMN_DATA: '|| :5|| 'DIFF_DATA : ' || :6 || ' SOC: ' ||:7|| '
FEATURE_CODE: ' ||:8|| ' FTR_REVENUE_CODE: ' ||:9|| ' PRIOD_CVRG_ST_DATE: ' ||:10|| '
PRIOD_CVRG_ND_DATE: ' ||:11|| ' ACTV_REASON_CODE: ' ||:12|| 'BALANCE_IMPACT_CODE: '|| :13 || '
SOURCE_APPL_CODE : ' || :14 || ' DISCOUNT_CD: '|| :15 || ' BILL_MEDIA : ' || :16|| 'BILL_FORMAT : '
|| :17 || ' PRODUCT_TYPE: ' ||:18|| ' FTR_TYPE ' ||:19 || ' VAL_ID ' ||:20 );
v_ban :=:1;
V_DISCOUNT_CD :=:15;
V_EXP_DATE :=:11;
dbms_output.put_line(V_DISCOUNT_CD);
dbms_output.put_line(V_EXP_DATE);
select 'comments_'|| :20 into v_comments from dual;
select 'val_done_by_'|| :20 into v_val_Done_by from dual;
DBMS_OUTPUT.Put_line(v_val_Done_by);
DBMS_OUTPUT.Put_line(v_comments);
SELECT HIERARCHY_ID INTO V_HIERARCHY_ID FROM BILLING_ACCOUNT WHERE BAN =:1;
IF V_HIERARCHY_ID IS NULL
THEN
SELECT COUNT(*) INTO V_COUNT FROM BAN_DISCOUNT WHERE BAN =:1 AND TRIM(DISCOUNT_CODE) =
V_DISCOUNT_CD AND EXPIRATION_DATE < V_EXP_DATE;
IF V_COUNT >= 1
THEN
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_1,v_yesnoind,v_success,v_ban;
COMMIT;
ELSE
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
COMMIT;
END IF;
ELSE
-- NODE LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_FATHER_ID FROM CH_ARCS WHERE ARC_CHILD_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
-- BAN LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID = V_HIERARCHY_ID
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
-- SUBSCRIBER LEVEL DISCOUNT CHECK
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_CHILD_ID FROM CH_ARCS WHERE ARC_FATHER_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = V_DISCOUNT_CD
AND VALID_TO < V_EXP_DATE;
IF V_COUNT >= 1
THEN
EXECUTE IMMEDIATE 'UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,' || v_val_Done_by || ' = :3, '
|| v_comments || ' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5'
using v_issue_Desc,v_comments_1,v_yesnoind,v_success,v_ban;
COMMIT;
ELSE
(I am facing the above error in this ELSE part in below line as it is going in this line 85)
EXECUTE IMMEDIATE ''UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,'' || v_VAL_DONE_BY || '' =
:3, '' || v_comments || '' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5''
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
COMMIT;
END IF;
END IF;
END;
(I am facing the above error in this ELSE part in below line as it is going in this line 85)
EXECUTE IMMEDIATE ''UPDATE BL_DIFF_CATEGORY SET VALIDATION_STS=:2,'' || v_VAL_DONE_BY || '' = :3, '' || v_comments || '' = :4 WHERE BAN = :1 AND DIFF_TYPE = :5''
using v_issue_Desc,v_comments_2,v_yesnoind,v_success,v_ban;
There seems to be some discrepancy between orders of the placeholders in the string and the parameters in the USING clause. For instance BAN = :1 is the fourth placeholder but v_ban is the fifth variable passed to the EXECUTE IMMEDIATE statement, whilst the value actually assigned to BAN is v_success.
Perhaps you simply need to review the placeholders and re-order the parameters? If so, remember to do the same for the statement in the IF branch.
Incidentally, the names of the placeholders in the string don't matter, but if you're going to use numbers you might as well put them in numeric order.
DISCOUNT_CD - NULL <== Null is not a valid number -- you need a coalesce here
eg
SELECT COUNT(*) INTO V_COUNT FROM CH_OBJECT_ATTRIBUTES
WHERE
OBJ_ID IN ( SELECT ARC_CHILD_ID FROM CH_ARCS WHERE ARC_FATHER_ID = V_HIERARCHY_ID)
AND ATTR_NAME = 'Discount Plans'
AND ATTR_VALUE = COALESCE(V_DISCOUNT_CD,0)
AND VALID_TO < V_EXP_DATE;

Teradata Stored Procedure variables

I'm trying to create a stored procedure to create all possible combination of a table with itself. For now, I got this code, but it produces the following error:
Syntax error: expected something between the word 'A' and the integer '2'
Code:
CREATE MULTISET TABLE PRUEBA
(
CAMPO VARCHAR(10)
);
INSERT INTO PRUEBA VALUES('A');
INSERT INTO PRUEBA VALUES('B');
INSERT INTO PRUEBA VALUES('C');
REPLACE PROCEDURE TEST()
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(255);
DECLARE i INT;
DECLARE n INT;
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || i ; -- Error in this part.
SET b = b || 'A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || i ;
SET b = b || 'AND A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
EXECUTE IMMEDIATE qry;
END;
CALL TEST();
I'd join the 'i' variable to create multiple alias for all cross tables.
Your i variable is an INTEGER. Try casting it as a VARCHAR() when you do your concatenations:
SET a = a || 'CROSS JOIN PRUEBA A' || CAST(i AS VARCHAR(2)) ; -- Error in this part.
SET b = b || 'A' || CAST((i-1) AS VARCHAR(2)) || '.CAMPO < A' ||
CAST(i AS VARCHAR(2)) || '.CAMPO';
You'll have to do this in the subsequent ELSE block as well.
Use explicit CAST or TRIM to avoid the leading blanks generated by implicit cast from INTEGER to VARCHAR. And you need to use a dynamic cursor to return the result of the SELECT to the caller.
REPLACE PROCEDURE TEST()
DYNAMIC RESULT SETS 1 --Allow returning data to caller
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(4096);
DECLARE i INT;
DECLARE n INT;
DECLARE csr1 CURSOR WITH RETURN FOR stmt1; --Declare a dynamic cursor
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'AND A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
PREPARE stmt1 FROM qry; --Prepare a dynamic SQL statement for the cursor
OPEN csr1; --Execute the SELECT statement
--Leave a WITH RETURN cursor open to return the result set
END;
if you're using bteq you might have to write the procedure into a file and load it with .compile directive.
once you are loggen in and supposing the file is /tmp/stored_procedure.sql
compile it like this:
.compile file='/tmp/stored_procedure.sql';

How to validate and print message when there is no data? PL SQL

Using PL/SQL I'm trying to validate and print a message when there's no data found on a cursor. My main problem is that if I use the %NOTFOUND it gets printed multiple times or along when data is found.
Here is my code:
set SERVEROUTPUT ON
set verify off
DECLARE
rut int;
CURSOR Ejercicio2 (rut int)
IS
SELECT alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre
FROM alumno
INNER JOIN alumnoramo ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
alumno_nombre VARCHAR2(45);
alumno_apellido VARCHAR2(45);
alumno_apellidoM VARCHAR2(45);
ramo_nombre VARCHAR2(45);
profesor_nombre VARCHAR2(45);
BEGIN
rut := '&rut';
OPEN Ejercicio2 (rut);
LOOP
FETCH Ejercicio2 INTO alumno_nombre,alumno_apellido,alumno_apellidoM,ramo_nombre,profesor_nombre;
EXIT WHEN Ejercicio2%NOTFOUND;
dbms_output.put_line('Nombre: ' || alumno_nombre);
dbms_output.put_line('Apellido: ' || alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || alumno_apellidoM);
dbms_output.put_line('Ramo: ' || ramo_nombre);
dbms_output.put_line('Profesor: ' || profesor_nombre);
END LOOP;
CLOSE Ejercicio2;
END;
When the user inputs a "rut" it should normally print the found data and end. If the input "rut" and no data is returned, then it should print a message and ending the program. I haven't being able to do so.
use the below code block .let me know if you get some error.I just wrote it on notepad and it should as I expect.
set SERVEROUTPUT ON
set verify off
DECLARE
rut int;
CURSOR Ejercicio2 (rut int)
IS
SELECT alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre
FROM alumno
INNER JOIN alumnoramo ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
TYPE Ejercicio2_typ IS TABLE OF Ejercicio2%ROWTYPE;
Ejercicio2_tbl Ejercicio2_typ;
BEGIN
rut := '&rut';
OPEN Ejercicio2 (rut);
FETCH Ejercicio2 BULK COLLECT INTO Ejercicio2_tbl;
IF Ejercicio2_tbl.count >0 THEN
FOR rec IN Ejercicio2_tbl.first..Ejercicio2_tbl.last LOOP
dbms_output.put_line('Nombre: ' || Ejercicio2_tbl(rec).alumno_nombre);
dbms_output.put_line('Apellido: ' || Ejercicio2_tbl(rec).alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || Ejercicio2_tbl(rec).alumno_apellidoM);
dbms_output.put_line('Ramo: ' || Ejercicio2_tbl(rec).ramo_nombre);
dbms_output.put_line('Profesor: ' || Ejercicio2_tbl(rec).profesor_nombre);
END LOOP;
ELSE
dbms_output.put_line('No data found');
END IF;
CLOSE Ejercicio2;
END;
/
Happy coding.
Mark it as an answer if it satisfy your needs.
Just a variation and a clean way of handling the scenario. Hope it helps.
CREATE OR REPLACE TYPE obj IS OBJECT
(
nombre VARCHAR2(100),
apellidoP VARCHAR2(100)
apellidoM VARCHAR2(100)
descripcion VARCHAR2(100)
nombre VARCHAR2(100)
);
CREATE OR REPLACE TYPE tab IS TABLE OF obj;
SET SERVEROUTPUT ON
SET verify OFF
DECLARE
rut INT:=&Enter_rut;
tab1 tab;
BEGIN
SELECT obj(alumno.nombre,alumno.apellidoP,alumno.apellidoM,Ramo.descripcion,profesor.nombre) BULK COLLECT
INTO tab1
FROM alumno
INNER JOIN alumnoramo
ON alumnoramo.cod_matricula = alumno.cod_matricula
INNER JOIN Ramo
ON ramo.cod_ramo = alumnoramo.cod_ramo
INNER JOIN profesor
ON profesor.cod_prof = ramo.cod_prof
WHERE alumno.cod_matricula = rut;
IF tab1.EXISTS(1) THEN
FOR I IN tab1.FIRST..tab1.LAST
LOOP
dbms_output.put_line('Nombre: ' || tab1(i).nombre);
dbms_output.put_line('Apellido: ' || tab1(i).apellidoP);
dbms_output.put_line('Apellido Materno: ' || tab1(i).apellidoM);
dbms_output.put_line('Ramo: ' || tab1(i).descripcion);
dbms_output.put_line('Profesor: ' || tab1(i).nombre);
END LOOP;
ELSE
dbms_output.put_line('no data found for the Input');
END IF;
END;
You could set a Boolean variable in the loop, and then check at the end whether it was true or false:
set define on
accept rut number prompt 'Introduza un identificador de class: '
var rut number
exec :rut := &rut
declare
cursor ejercicio2
( cp_rut int )
is
select alumno.nombre as alumno_nombre
, alumno.apellidop as alumno_apellido
, alumno.apellidom as alumno_apellidom
, ramo.descripcion as ramo_nombre
, profesor.nombre as profesor_nombre
from alumno
join alumnoramo
on alumnoramo.cod_matricula = alumno.cod_matricula
join ramo
on ramo.cod_ramo = alumnoramo.cod_ramo
join profesor
on profesor.cod_prof = ramo.cod_prof
where alumno.cod_matricula = cp_rut;
l_encontro boolean := false;
begin
for r in ejercicio2(:rut)
loop
l_encontro := true;
dbms_output.put_line('Nombre: ' || r.alumno_nombre);
dbms_output.put_line('Apellido: ' || r.alumno_apellido);
dbms_output.put_line('Apellido Materno: ' || r.alumno_apellidom);
dbms_output.put_line('Ramo: ' || r.ramo_nombre);
dbms_output.put_line('Profesor: ' || r.profesor_nombre);
end loop;
if not l_encontro then
dbms_output.put_line('No se encontraron las classes por rut ' || :rut);
end if;
end;
/
(Excuse my Google Spanish.)
Or you could make it a numeric value initialised to 0 and report the number of rows processed.

Oracle SQL - Alternative for dynamic query

I have a procedure (see below) which is using dynamic query. I wanted to rewrite this procedure with out using dynamic query. How do I write the conditions below?
PROCEDURE DemoProcedure(p_firstname IN VARCHAR2,
p_lastname IN VARCHAR2,
p_phone IN VARCHAR2
o_Cursor OUT t_Cursor) IS
SQLString VARCHAR2(4000);
BEGIN
SQLString :=
'SELECT * FROM
SCHEMA.TABLENAME_a A
INNER JOIN SCHEMA.TABLENAME_b B
ON A.ID = B.ID
WHERE
A.TYPE = 1 ';
IF p_firstname IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.FIRST_NAME) like UPPER( ''' || p_firstname || ''')';
END IF;
IF p_lastname IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.LAST_NAME) like UPPER( ''' || p_lastname || ''')';
END IF;
IF p_phone IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.PHONE) = ''' ||
p_phone || '''';
END IF;
SQLString := SQLString || ' order by a.id ';
OPEN o_Cursor FOR SQLString;
END DemoProcedure;
It looks like you just want
OPEN o_cursor
FOR SELECT ...
WHERE A.TYPE = 1
AND (p_firstname IS NULL or upper(a.first_name) = upper(p_firstname))
AND (p_lastname IS NULL or upper(a.last_name) = upper(p_lastname))
AND (p_phone IS NULL or upper(a.phone) = p_phone)
ORDER BY a.id
I'm not sure why you'd want to bother upper-casing a phone number-- do you have character data in a phone number?
Different way writing the same SQL as #JustinCave suggested -
OPEN o_cursor
FOR SELECT ...
WHERE A.TYPE = 1
AND upper(a.first_name) = nvl(upper(p_firstname), upper(a.first_name))
AND upper(a.last_name) = nvl(upper(p_lastname),upper(a.last_name))
AND upper(a.phone) = nvl(p_phone,upper(a.phone))
ORDER BY a.id