Oracle PL/SQL function: if parameter not in table column => continue program - oracle

Please see my code below. If the parameter p_cust_id is not in the column cust_id I want "0" to be printed out (which means not logged in). If it is in cust_id I want oracle to continue the second part of the code (the part below the empty row).
I have tried to solve this by inserting the values of column cust_id in a cursor and then inserting it in the variable v_cust_id. Perhaps this results in unnecessarily much code?
My problem is that the program does not seem to run the second part even if p_cust_id is in cust_id. It just prints out "0" even though the customer ID and the password are correct.
Before I added the cursor the program worked as it was supposed to, unless the parameter p_cust_id didn't match any value in the cust_id column. If this was the case nothing was printed out.
create or replace function log_in(
p_cust_id in customer.cust_id%type,
p_passwd in customer.passwd%type)
return varchar2
as
cursor c_cust_id is select cust_id from customer;
v_cust_id customer.cust_id%type;
v_passwd customer.passwd%type;
v_logged_in number(1);
v_not_logged_in number(1);
begin
v_logged_in := 1;
v_not_logged_in := 0;
if not c_cust_id%isopen then
open c_cust_id;
end if;
loop
fetch c_cust_id
into v_cust_id;
exit when c_cust_id%notfound;
end loop;
if p_cust_id not in(v_cust_id) then
return v_not_logged_in;
end if;
close c_cust_id;
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
if v_passwd = p_passwd then
return v_logged_in;
else
return v_not_logged_in;
end if;
end;

I could see, you don't need a cursor at all, to check if the cust_id is in the table. Just search for the cust_id in the table, and attempt to fetch the password. If it exists, you get the value, and NO_DATA_FOUND exception otherwise which means not logged in.
BEGIN
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
return v_not_logged_in;
END;
Full code will be:
create or replace function log_in(
p_cust_id in customer.cust_id%type,
p_passwd in customer.passwd%type)
return varchar2
as
v_cust_id customer.cust_id%type;
v_passwd customer.passwd%type;
v_logged_in number(1);
v_not_logged_in number(1);
begin
v_logged_in := 1;
v_not_logged_in := 0;
BEGIN
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
return v_not_logged_in;
END;
if v_passwd = p_passwd then
return v_logged_in;
else
return v_not_logged_in;
end if;
end;

Related

inserting data select into with loop in plsql

I am just want to enter forms detail column data into a database column from a detail block and that must check first entered data which it already have in that column when i entered data data saves in other tables but in token_staus is not entering data and message me No data found for that i write a loop which is not working for me i am making some kind of mistake obviously but not sure where it is
DECLARE
TOKEN_NO NUMBER;
TOKEN_STATUS1 NUMBER;
--TOKEN_STATUS2 := :TOKEN_STATUS;
BEGIN
SELECT SR_NO, TOKEN_STATUS INTO TOKEN_NO, TOKEN_STATUS1 FROM LOOPT2 WHERE SR_NO = :TOKEN_NO;
--IF :TOKEN_STATUS IS NULL
--THEN
LOOP
GO_BLOCK('TOKEN_REC2');
FIRST_RECORD;
INSERT INTO LOOPT2(TOKEN_STATUS) VALUES(:TOKEN_STATUS);
NEXT_RECORD;
EXIT WHEN :SYSTEM.LAST_RECORD = 'TRUE';
END LOOP;
--END IF;
EXCEPTION
when others then
message (sqlerrm);
END;
Please help me
Little Foot please
If I understood you correctly, it would be something like this (check comments within the code): key thing here seems to be a BEGIN-EXCEPTION-END block within the LOOP.
DECLARE
TOKEN_NO NUMBER;
TOKEN_STATUS1 NUMBER;
BEGIN
GO_BLOCK('TOKEN_REC2');
FIRST_RECORD;
LOOP
BEGIN
SELECT SR_NO, TOKEN_STATUS
INTO TOKEN_NO, TOKEN_STATUS1
FROM LOOPT2
WHERE SR_NO = :TOKEN_NO;
-- if such a :TOKEN_NO exists, that SELECT will return some values
-- which means that you want to skip it, so - don't do anything
EXCEPTION
-- if such a :TOKEN_NO does not exist, SELECT will return
-- NO_DATA_FOUND which means that you want to perform insert
WHEN NO_DATA_FOUND THEN
INSERT INTO LOOPT2 (TOKEN_STATUS)
VALUES (:TOKEN_STATUS);
WHEN TOO_MANY_ROWS THEN
NULL;
END;
EXIT WHEN :SYSTEM.LAST_RECORD = 'TRUE';
NEXT_RECORD;
END LOOP;
END;

Validation of result before executing the query

When running a stored procedure to fetch some rows, First I want to validate if the query will return a row before sending the result, and second if it is possible to validate without running the same query twice.
I am using a cursor to store the yielded result, So I tried the cursor attribute %ROWCOUNT & %NOTFOUND. But the doesnt quite work. Plus I want to do this without running a loop on the cursor.
procedure MODULE_LIST_GK(p_module_Id IN MODULE_LIST.MODULE_ID% TYPE,
p_Error_Code out nvarchar2,
p_Error_Msg out nvarchar2,
p_Cursor out sys_refcursor) IS
BEGIN
OPEN p_Cursor FOR
SELECT A.MODULE_ID,
A.MODULE_NM,
A.AUTH_STATUS_ID
FROM MODULE_LIST A
WHERE A.MODULE_ID=p_module_Id;
SELECT COUNT(MODULE_ID)
INTO v_row_num
FROM MODULE_LIST A
WHERE A.MODULE_ID=p_module_Id;
IF v_row_num=0 THEN
p_Error_Code := SQLCODE;
p_Error_Msg := 'Does not Exists';
Return;
end IF;
EXCEPTION
WHEN OTHERS THEN
p_error_code:= SQLCODE;
p_error_msg := SQLERRM;
END MODULE_LIST_GK;
Your implementation have several points that could be improved.
First if you expect that for lot of parameters the returned cursor will be empty,
than first check the empty cursor and only after this check open the cursor. You do it vice versa.
How to check if the cursor is empty? Unfortunatelly you must fetch the first row to be able to verify it.
open l_cur for
select id, status from tab where id = p_id;
fetch l_cur into l_id, l_status;
if l_cur%NOTFOUND then
p_Error_Msg := 'Does not Exists';
Return;
end if;
This check is far more effective that the often used count(*) as it is considering only the first (few) rows and not counting all rows in the cursor.
If the check fails you are ready, othervise simple open the cursor and return it.
open l_cur for
select id, status from tab where id = p_id;
p_Cursor := l_cur;
Two additional thinks come to mind.
You should rething the generall approach if the database is very dynamic. How would you handle the case when other session deletes some row between the check and the second open of the cursor?
Finally consider returning an exception instead of the return code.
In order to know whether a cursor contains rows, you must open it and fetch the first row. Once you've done this, it makes no sense anymore to return that cursor, for the recipient will not be able to fetch that first row, because the cursor already points beyond it.
So, you must select twice. What you'd do is to use ROWNUM or an EXISTS clause here to show the DBMS that you are not interested in any more rows. This can speed up the query extremely.
PROCEDURE module_list_gk(p_module_id IN MODULE_LIST.MODULE_ID%TYPE,
p_error_code OUT NVARCHAR2,
p_error_msg OUT NVARCHAR2,
p_cursor OUT SYS_REFCURSOR) IS
v_count INTEGER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM module_list
WHERE module_id = p_module_Id
AND ROWNUM = 1;
IF v_count = 0 THEN
p_error_code := 0; -- Or -1403 for NO DATA FOUND if you like
p_error_msg := 'Does not Exists';
RETURN;
END IF;
OPEN p_Cursor FOR
SELECT module_id, module_nm, auth_status_id
FROM module_list
WHERE module_id = p_module_id;
EXCEPTION WHEN OTHERS THEN
p_error_code:= SQLCODE;
p_error_msg := SQLERRM;
END module_list_gk;
SQLCODE for the first query will be 0 by the way (SELECT COUNT(*) returns one row with the number of records found - no error hence). This is why you should decide to either return zero explicitly or some error code, such as -1403.
Here is the same with EXISTS:
BEGIN
SELECT CASE WHEN EXISTS
(
SELECT NULL
FROM module_list
WHERE module_id = p_module_Id
) THEN 1 ELSE 0 END
INTO v_count
FROM DUAL;
IF v_count = 0 THEN

How to count rows from two columns?

I try to create the function login that takes customer number(pnr) and password from same table. Its fine to create function but test crashes with following eror:
ORA-00904: "P_PASSWD": invalid identifier
create or replace function logga_in(
p_pnr bankkund.pnr%type,
p_passwd bankkund.passwd%type
)
return number
as
v_resultat number(1);
begin
select count(pnr) into v_resultat
from bankkund
where p_pnr = pnr
and p_passwd = passwd;
return 1;
exception
when no_data_found then
return 0;
end;
There is one other problem with your code not suggested in the comments, A count function from a select into will not raise a NO_DATA_FOUND exception. You may use an IF condition on count or do something like this, which is preferable
CREATE OR REPLACE FUNCTION logga_in (
p_pnr bankkund.pnr%TYPE,
p_passwd bankkund.passwd%TYPE
) RETURN NUMBER AS
v_resultat NUMBER(1);
BEGIN
SELECT 1 --do not use count if you wish to handle no_data_found
INTO v_resultat FROM
bankkund WHERE pnr = p_pnr AND
passwd = p_passwd
AND ROWNUM = 1; --Add this
RETURN 1;
EXCEPTION
WHEN no_data_found THEN
RETURN 0;
END;
Now, as far as calling the procedure is concerned, there are various options available including using bind variable
VARIABLE p_pnr number --use the datatype of bankkund.pnr%TYPE
VARIABLE p_passwd VARCHAR2(10) --use the datatype of bankkund.passwd
SELECT logga_in(:p_pnr,:p_passwd) FROM dual;
Or substitution variable
SELECT logga_in('&p_pnr','&p_passwd') FROM dual;
Give inputs when prompted.
Or use PL/SQL block
DECLARE
v_res INT;
v_pnr bankkund.pnr%type := 12892; --or appropriate value
p_passwd bankkund.passwd%type := some_passwd';
BEGIN
v_res := logga_in();
If v_res = 1 THEN
do_something_u_want; --call or execute appropriate action.
END IF;
END;
/

Second statement in begin block is not executed

I have written this stored procedure in Oracle:
CREATE OR REPLACE FUNCTION GET_SOLVER_ID(username_in IN VARCHAR2)
RETURN NUMBER
IS
solver_id number(19);
system_user_id number(19);
BEGIN
SELECT id
INTO solver_id
FROM usr_solver
WHERE username = username_in;
select ID into system_user_id from USR_USER where USER_TYPE = 'X';
solver_id := nvl(solver_id, system_user_id);
RETURN(solver_id);
END;
When I call the function with username that doesn't exist in table usr_solver I get null for the result. I expect to get system_user_id instead.
It seems like the other select statement and nvl function in begin block didn't execute.
Could you help, I can't see the reason why...
Thanks,
mismas
This should do what you want
CREATE OR REPLACE FUNCTION GET_SOLVER_ID(
username_in IN VARCHAR2)
RETURN NUMBER
IS
some_id NUMBER(19);
BEGIN
BEGIN
SELECT id
INTO some_id
FROM usr_solver
WHERE username = username_in;
EXCEPTION
WHEN NO_DATA_FOUND THEN
SELECT ID
INTO some_id
FROM USR_USER
WHERE USER_TYPE = 'X';
END;
RETURN(some_id);
END;

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;

Resources