String Comparision in If condition in PL/SQL - for-loop

I have the following code
create or replace procedure deact_user (i_email in varchar2)
as
var1 varchar2(200);
begin
for em_id in (select abc.emai_id from abc)
loop
if (i_email <> em_id) then
dbms_output.put_line('Not working');
else
dbms_output.put_line('Working');
end if;
end loop;
end;
I need to compare the i_email which is a input parameter with em_id which is a for loop which loops the table abc having field as emai_id.
Iam facing error PLS=00306 wrong type of arguments in call to '!='
Please help

When you use a for loop with select, its creates a record type. To access the value, you have to change your if to this:
if (I_email <> em_id.emai_id)
.....
That should solve your problem. Now, on the other hand, it would be quicker (and easier) to just query with a where clause using your variable. (that way, you wouldn't need a for loop).

I recommend you to use Cursors for read content and compare values like this:
create or replace procedure deact_user (i_email in varchar2)
as
var_id varchar2(200);
cursor cur_em_id is select abc.emai_id from abc;
begin
open cur_em_id;
loop
fetch cur_em_id into var_id;
exit when cur_em_id%NOTFOUND;
if (i_email <> var_id) then
dbms_output.put_line('Not working');
else
dbms_output.put_line('Working');
end if;
end loop;
close cur_em_id;
end;

Related

how do I use if condition in cursor because our professor don't allow us use where clause in the select statement

Our question is showing all the countries that have names that are exactly 5 letter long. This is the cursor code and I want add if condition into it.
declare
cursor cursor_full is select * from country_cont;
begin
for counter in cursor_full
loop
dbms_output.put_line(counter.country|| ' ' || counter.continent);
end loop;
end;
However my professor said that you can't using where clause within the select statement and you should display all the countries and continent.
so i tried this code:
declare
country varchar(50);
cursor cursor_full is select * from country_cont;
begin
if length(country)=5 then
for counter in cursor_full
loop
dbms_output.put_line(counter.country|| ' ' || counter.continent);
end loop;
end if;
end;
the script output show that PL/SQL procedure successfully completed but nothing return in DBMS output
Hope someone can help me, I spent whole night to think about it,please!
Variable country doesn't contain any value, it is null so if condition is never true and loop is never executed. Sample data would help; meanwhile, see if this helps.
begin
for cur_r in (select * from country_cont) loop
if length(cur_r.country) > 5 then
dbms_output.put_line(cur_r.country|| ' ' || cur_r.continent);
end loop;
end;
Don't forget to set serveroutput on.

Input table and column name in Oracle SQL

I want to complete a task that says:
Search in the user given table, in the user given column the user given value using explicite cursor. This means I have to use the & operator to input the table name, column name and value. If I found the given object, give a varchar found else not found. How to input the table name, column name and the value (that is of correct type of course)?
I tried it but failed miserably:
declare
#Mytable varchar2;
#Mycolumn varchar2;
Myvalue #Mycolumn%TYPE;
oneLine #Mytable%ROWTYPE;
found varchar2;
cursor kurzor is select * from #Mytable;
begin
open kurzor;
loop
fetch kurzor into oneLine;
if oneLine.#Mycolumn = Myvalue then
found='found';
end if;
exit when kurzor%NOTFOUND;
end loop;
close kurzor;
end;
/
You don't need to describe variables for table name, column name and etc. in section DECLARE. Just use substitution variables.
DECLARE
CURSOR cur IS SELECT &myColumn FROM &myTable;
currentVal VARCHAR2(4000);
isFound VARCHAR2(10):= 'not found';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO currentVal;
EXIT WHEN cur%NOTFOUND;
IF currentVal = &myValue THEN
isFound:= 'found';
EXIT;
END IF;
END LOOP;
CLOSE cur;
dbms_output.put_line(isFound);
END;

Using like with varchar2 that have null value at start

The following is excerpt from my procedure that creates logical backup after checking the backup_schedule value in schema_info table:
CREATE OR REPLACE PROCEDURE BACKUP_EXECUTE
(
[...]
) AS
[...]
schemas varchar2(255):=' ';
cursor schema_name is select upper(schema_name) schema_name from schema_info
where backup_schedule like '%'||to_char(sysdate, 'D')||'%'
and exists (select * from dba_users where username=upper(schema_name));
type sl is table of schema_name%ROWTYPE
index by pls_integer;
schema_list sl;
BEGIN
open schema_name;
fetch schema_name bulk collect into schema_list;
close schema_name;
if schema_list.count != 0 then
for indx in 1..schema_list.count loop
if(schemas not like '%'||schema_list(indx).schema_name||'%') then
if indx>1 then
schemas:=schemas||',';
else
schemas:=null;
end if;
schemas:=schemas||''''||schema_list(indx).schema_name||'''';
end if;
end loop;
[...]
end if;
EXCEPTION
[...]
END;
Besides the fact, that this can be done better, I want to concentrate on one thing. As we know like is not working with null values. Should I leave the code as above and write some start value which later is deleted or is it better to use nvl(schemas,' ') in if statement?

Pass cursor name from a variable

I have a package that contains a procedure(takes an input parameter;cursor name) and two cursors.
The procedure is to use the cursor specified by the input parameter
PROCEDURE insertdetails(typ IN VARCHAR2) IS
BEGIN
OPEN typ;
LOOP
FETCH typ INTO colA;
EXIT WHEN typ%notfound;
--MISSING CODE
END LOOP;
END;
if i run the procedure and pass on of the name of the cusrsor as an input parameter i get the error PLS-00456: item 'TYP' is not a cursor
Is their a way out of this
You will need to use REF CURSORS to do this. Here's a pretty good explanation.
Your procedure definition would look like this:
PROCEDURE insertdetails(typ IN sys_refcursor) IS
You would probably not open the cursor in this procedure, generally you open it elsewhere, in the code where the cursor is defined.
Assuming the cursors are declared elsewhere in the package, you could use the parameter to decide which actual cursor to work with, something like:
PROCEDURE insertdetails(typ IN VARCHAR2) IS
BEGIN
IF typ = 'CURSOR_A' THEN
OPEN cursor_a;
LOOP
FETCH cursor_a INTO colA;
EXIT WHEN cursor_a%notfound;
--MISSING CODE
END LOOP;
ELSE
OPEN cursor_b;
LOOP
FETCH cursor_b INTO colA;
EXIT WHEN cursor_b%notfound;
--MISSING CODE
END LOOP;
END IF;
END;
Or if the missing code is common, as seems likely:
PROCEDURE insertdetails(typ IN VARCHAR2) IS
BEGIN
IF typ = 'CURSOR_A' THEN
OPEN cursor_a;
ELSE
OPEN cursor_b;
END IF;
LOOP
IF typ = 'CURSOR_A' THEN
FETCH cursor_a INTO colA;
EXIT WHEN cursor_a%notfound;
ELSE
FETCH cursor_b INTO colA;
EXIT WHEN cursor_b%notfound;
END IF;
--MISSING CODE
END LOOP;
END;
Either way you might prefer a case over an if; particularly if the number of possible cursors that typ can represent grows.

Need an alternative solution to this oracle query?Without using (flag) variable

Question:
Create a Doctor table (Docname, Qualification, Specialization, Working_shift).
Use parameterized cursor to check the availability of doctors given the specialization
and working shift of the day to serve the patients
I am just learning databases so if the question may seem trivial i apologize for that.
Getting the desired output on inputting the values but i need an alternative way to solve the question without using flag variable (so that i could get the exception)...if i don't use the flag it prints the exception as well as the docname and qualification
I am using oracle(cursor in a normal pl/sql block) to execute this query.
Solution:
--table creation
create table doctor
(
docname varchar2(20),
qualification varchar2(20),
specialization varchar2(20),
shift varchar2(20)
)
my solution
declare
cursor c1 (specialization varchar2,shift varchar2) is select docname,qualification from doctor
where specialization='&sp' and shift='&shift'
sp doctor.specialization%type;
shift doctor.shift%type;
flag number(10);
begin
flag:=0;
for r1 in c1(sp,shift)
loop
if c1%found then
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
else
flag:=0;
end if;
end loop;
if flag=0 then
dbms_output.put_line('Invalid specialization/shift');
end if;
end;
Try given below code
declare
cursor c1 (specialization varchar2,shift varchar2)
is
select docname,qualification
from doctor
where specialization='&sp'
and shift='&shift'
sp doctor.specialization%type;
shift doctor.shift%type;
flag number(10);
begin
flag:=0;
for r1 in c1(sp,shift)
loop
if c1%found then
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
else
raise;
end if;
end loop;
exception
when others then
dbms_output.put_line('Invalid specialization/shift');
end;
You don't need to reset the flag within the loop, you already initialised it to 0 at the start of the procedure.
You dont need to check c1%found because you're inside the loop; by definition a record was found, otherwise it wouldn't go into your loop code.
Your cursor should use the variables provided, not the SQL*Plus substitution variables, e.g.:
cursor c1 (specialization varchar2,shift varchar2) is
select docname,qualification
from doctor
where doctor.specialization=c1.specialization
and doctor.shift=c1.shift;
If you don't want to have to use all those aliases, you can use a naming convention to distinguish between the different identifiers (shift vs shift), e.g.:
cursor c1 (i_specialization varchar2, i_shift varchar2) is
select docname,qualification
from doctor
where specialization=i_specialization
and shift=i_shift;
Note also, you missed a semicolon at the end of the query.
Finally:
If you change your loop as follows, it should work fine:
for r1 in c1(&sp,&shift)
loop
flag:=1;
dbms_output.put_line('Doctor is available');
dbms_output.put_line('Docname: '||r1.docname);
dbms_output.put_line('qualification: '||r1.qualification);
end loop;
Now, your last bit of code:
if flag=0 then
dbms_output.put_line('Invalid specialization/shift');
end if;
will work fine - it will only execute if flag is still 0 (i.e. the query found no rows).
If you do not use parameters in "c1" cursor you do not need it...
DECLARE
CURSOR c1 IS
SELECT docname, qualification
FROM doctor
WHERE specialization = '&sp'
AND shift = '&shift';
TYPE c1_ntt IS TABLE OF c1%ROWTYPE;
l_c1 c1_ntt;
BEGIN
OPEN c1;
FETCH c1 BULK COLLECT INTO l_c1;
CLOSE c1;
IF l_c1.COUNT = 0 THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid specialization/shift');
END IF;
FOR indx IN l_c1.FIRST..l_c1.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Doctor is available');
DBMS_OUTPUT.PUT_LINE('Docname: ' || l_c1(indx).docname);
DBMS_OUTPUT.PUT_LINE('qualification: ' || l_c1(indx).qualification);
END LOOP;
END;

Resources