Hi all i have the code below :
CREATE OR REPLACE FUNCTION GET_STATE_USER (user_id IN NUMBER)
RETURN VARCHAR2
AS
staffName VARCHAR2 (50);
BEGIN
DBMS_OUTPUT.put_line(user_id);
SELECT bs.FIRST_NAME || ' ' || bs.LAST_NAME
INTO staffName
FROM EMPLOYEE e
WHERE bs.USER_ID = user_id;
RETURN (CASE
WHEN staffName IS NOT NULL THEN staffName
ELSE 'Invalid'
END);
END;
/
And I'm getting following error :
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "GET_STATE_USER", line 8
You must change the name of the input variable. The variable name must not be the same as the table column name.
try this :
CREATE OR REPLACE NONEDITIONABLE FUNCTION GET_STATE_USER (user__id IN NUMBER)
RETURN VARCHAR2
AS
staffName VARCHAR2 (50);
BEGIN
DBMS_OUTPUT.put_line(user__id);
SELECT bs.FIRST_NAME || ' ' || bs.LAST_NAME
INTO staffName
FROM EMPLOYEE bs
WHERE bs.USER_ID = user__id;
RETURN (CASE
WHEN staffName IS NOT NULL THEN staffName
ELSE 'Invalid'
END);
END;
Actually I wanted to check two tables for existence of a record and finally the code below did the trick :
CREATE OR REPLACE FUNCTION GET_STATE_USER (userId IN NUMBER)
RETURN VARCHAR2
AS
r_count NUMBER;
userTitle VARCHAR2 (100);
BEGIN
SELECT COUNT (1)
INTO r_count
FROM EMPLOYEE bs
WHERE bs.USER_ID = userId;
IF r_count > 0
THEN
SELECT bs.FIRST_NAME || ' ' || bs.LAST_NAME
INTO userTitle
FROM EMPLOYEE bs
WHERE bs.USER_ID = userId;
ELSE
SELECT ac.name
INTO userTitle
FROM allcustomer ac
WHERE ac.CUSTOMER_USER_ID = userId;
END IF;
RETURN (CASE
WHEN userTitle IS NOT NULL THEN userTitle
ELSE 'inavlid'
END);
END;
/
Related
I have create a PL/SQL stored procedure from which I want to return output and display it.
I want to return the output either the success or failure message into variable : MSG
How do I need to do this any idea
PL/SQL code:
CREATE OR REPLACE PROCEDURE CHECKFILED
(
MY_NAME EMP.FIRSTNAME%TYPE,
MY_ID EMP.ID%TYPE
) RETURN VARCHAR2
IS
V_MSG VARCHAR(4000 CHAR);
BEGIN
SELECT FIRSTNAME INTO MY_NAME FROM EMP WHERE ID=MY_ID;
IF MY_NAME IS NOT NULL THEN
INSERT INTO CUSTOMER VALUES (UID,FIRSTNAME);
V_MSG='FIELD IS NOT EMPTY';
ELSE
RAISE_APPLICATION_ERROR(-20000,'FIELD IS EMPTY');
END IF;
EXCEPTION
WHEN OTHERS THEN
V_MSG := SQLCODE || '-' || SQLERRM;
RETURN(V_MSG);
RETURN(V_MSG);
END;
Calling the stored procedure:
DECLARE
MSG VARCHAR2(4000 CHAR);
BEGIN
SELECT CHECKFILED('10A') AS MSG FROM DUAL;
END;
If it is a procedure, it should have an OUT parameter which will then be used to return some value.
Something like this; note that it is probably useless to check whether select returned null (employees do have names; select would return no row and therefore raise no_data_found exception).
CREATE OR REPLACE PROCEDURE checkfiled (my_id IN emp.id%TYPE,
v_msg OUT VARCHAR2)
IS
my_name emp.firstname%TYPE;
BEGIN
SELECT firstname
INTO my_name
FROM emp
WHERE id = my_id;
INSERT INTO customer
VALUES (UID, firstname);
v_msg := 'FIELD IS NOT EMPTY';
EXCEPTION
WHEN OTHERS
THEN
v_msg := SQLCODE || '-' || SQLERRM;
END;
You'd then call it as
DECLARE
msg VARCHAR2 (4000 CHAR);
BEGIN
checkfiled ('10A', msg);
DBMS_OUTPUT.put_line ('Procedure returned ' || msg);
END;
/
PROCEDUREs do not have any return value. If you want to return a value, it needs to be a FUNCTION. Try the code below.
CREATE OR REPLACE FUNCTION CHECKFILED (MY_NAME EMP.FIRSTNAME%TYPE, MY_ID EMP.ID%TYPE)
RETURN VARCHAR2
IS
V_MSG VARCHAR (4000 CHAR);
BEGIN
SELECT FIRSTNAME
INTO MY_NAME
FROM EMP
WHERE ID = MY_ID;
IF MY_NAME IS NOT NULL
THEN
INSERT INTO CUSTOMER
VALUES (UID, FIRSTNAME);
V_MSG := 'FIELD IS NOT EMPTY';
ELSE
RAISE_APPLICATION_ERROR (-20000, 'FIELD IS EMPTY');
END IF;
RETURN (V_MSG);
EXCEPTION
WHEN OTHERS
THEN
V_MSG := SQLCODE || '-' || SQLERRM;
RETURN (V_MSG);
END;
I'm new to PL/SQL. Can anyone please help fix my compilation error? Your help is much appreciated. Also, after I would like to call this procedure to check and add a new user.
create or replace procedure CheckAddUser ( userid in varchar2(20))
as
declare vartmp number;
begin
SELECT nvl((SELECT distinct 1 FROM crm_admin.LTY_USER_STORE WHERE usr_nm = userid ), 0) INTO :varTmp FROM dual;
IF (:varTmp = 0) THEN
dbms_output.put_line('the user ' || ':userid' || ' does not exist');
elsif (:varTmp = 1) THEN
dbms_output.put_line('the user ' || ':userid' || ' already exist');
End if;
end;
Try this:
create or replace procedure checkadduser(userid in varchar2)
as
vartmp number;
begin
select coalesce(max(1), 0) into vartmp
from dual
where exists (
select 1
from crm_admin.lty_user_store
where usr_nm = userid
);
if vartmp = 0 then
dbms_output.put_line('the user ' || userid || ' does not exist');
elsif vartmp = 1 then
dbms_output.put_line('the user ' || userid || ' already exist');
end if;
end;
/
Changes made:
Removed the size from parameter
Removed the declare keyword - not part of the procedure syntax
Modified the query to stop searching as soon as a row is found and return 1 otherwise 0.
select coalesce(max(1), 0) into varTmp
from dual
where exists (
select 1
from crm_admin.lty_user_store
where usr_nm = userid
);
If the usr_nm is unique in your table, this will work well too (this can be used even if it's not unique but can be bit less performant if number of rows per usr_nm can be arbitrarily large):
select coalesce(max(1), 0)
into varTmp
from crm_admin.lty_user_store
where usr_nm = userid
Do not use : with the variables and parameters.
Don't use ":" with var.
I did some changes, which I would migth use:
--I recommended to change procedure to function, then you can use it in SQL
create or replace
procedure CheckAddUser ( userid in varchar2)
as
--Best practics, use self-describing variables
isuserexist number(1,0); -- vartmp
message_suff varchar2(30):=' does not exist';
begin
--Best practics, first check the parameters
if trim(userid) is null then
raise_application_error(-20000, 'Param userid is empty');
end if;
select count(*) into isuserexist
from crm_admin.lty_user_store
where usr_nm = userid;
--only one if, reads easier
if isUserExist > 0 then
message_suff:= ' already exist';
end if;
dbms_output.put_line('the user ' || ':userid' || message_suff);
end;
I’m write one function funGetAccount’ inOracle Pl-Sql` passing parameter ProdCd but query has consider its statement how it solved I’m not understand my req is same query pls don’t change the query design.
Function funGetAccount (ProdCd in Number)
Return Varchar2 Is
varResult Varchar2(2000);
Begin
varResult := ' Select AC_NO, NAME From ('
|| ' Select AC_NO, NAME'
|| ' From Tab1 Where PRODUCT_CD = ProdCd)';
varResult := varResult;
Return varResult;
End funGetAccount;
This will return AC_NO and NAME concatenated by space. You cannot return 2 values from it.
Also make sure that your query is returning only 1 row for the given prodcd else it return only first row.
create or replace function funGetAccount (ProdCd in Number)
Return Varchar2 Is
varResult Varchar2(2000);
Begin
Select AC_NO||' '||NAME
into varResult
From Tab1 Where PRODUCT_CD = ProdCd and rownum <2;
Return varResult;
End funGetAccount;
I don't understand what definitely you want to archive with this function: return select statement or retrieve data.
In the first case you should do:
Function funGetAccount (ProdCd in Number)
Return Varchar2
Is
varResult Varchar2(2000);
Begin
varResult := ' Select AC_NO, NAME From ('
|| ' Select AC_NO, NAME'
|| ' From Tab1 '
|| ' Where PRODUCT_CD = ' || ProdCd || ')';
Return varResult;
End funGetAccount;
In the second (retrieve data)
create or replace function funGetAccount (ProdCd in Number)
Return Varchar2
Is
varResult Varchar2(2000);
Begin
Select AC_NO||' '||NAME
into varResult
From Tab1
Where PRODUCT_CD = ProdCd;
Return varResult;
End funGetAccount;
As per the question i can see there are two requirements which can come into picture.
1) OP wants to return the raw SQL statement through FUNCTION.
2) OP wants SQL output in CONCATENATED WAY.
I have focused on 2 point where i have incorporated some of the good coding practices like EXCEPTION Handling. Hope it helps.
FUNCTION funGetAccount(
ProdCd IN NUMBER)
RETURN VARCHAR2
IS
p_result_out VARCHAR2(100);
varResult VARCHAR2(2000);
BEGIN
varResult := 'Select AC_NO||'',''||NAME From
( Select AC_NO, NAME From Tab1 Where PRODUCT_CD = '''||ProdCd||''')';
BEGIN --> Exception handling missed
EXECUTE IMMEDIATE varResult INTO p_result_out;
EXCEPTION
WHEN OTHERS THEN --> Others is broad term you can catch specific exceptions like no data found too many rows etc
NULL; -- Your action logic
END;
RETURN p_result_out;
END funGetAccount;
Function funGetAccount (ProdCd in Number)
Return Varchar2 Is
varResult Varchar2(2000);
Begin
varResult := ' Select AC_NO, NAME From ('
|| ' Select AC_NO, NAME'
|| ' From Tab1 Where PRODUCT_CD = '''|| ProdCd ||''')';
varResult := varResult;
Return varResult;
End funGetAccount;
I tried to create an Oracle function where table name, column name and where string are dynamic parameters:
CREATE OR REPLACE FUNCTION MYSCHEMA.myFunctionName(
tableName in nvarchar2,
columnName in nvarchar2,
whereStr in nvarchar2)
RETURN nvarchar2
IS nActive nvarchar2(2000);
BEGIN
declare
querystr nvarchar2(2000) ;
result nvarchar2(2000);
begin
querystr :='
select listagg('+columnName+','+','+') within group (order by '+columnName+')
from '+tableName+' where 1 = 1 '+whereStr+';';
EXECUTE IMMEDIATE querystr
INTO result;
nActive := result;
RETURN ( nActive );
end;
END ;
/
But it gives me error "Warning: compiled but with compilation errors".
What am I doing wrong?
For concatenate strings in Oracle use || not +
You don't need ; at the end of execute immediate query string
You need to escape ' using ''.
... as #Aleksej said
Execute immediate need query string in CHAR or VARCHAR2;
listagg return either raw or VARCHAR2
CREATE OR REPLACE FUNCTION MYSCHEMA.myFunctionName(
tableName in varchar2,
columnName in varchar2,
whereStr in varchar2)
RETURN varchar2
BEGIN
declare
querystr varchar2(2000) ;
result varchar2(2000);
begin
querystr :='
select listagg('|| columnName || ', '','') within group (order by ' ||columnName ||')
from ' || tableName || ' where 1 = 1 ' || whereStr;
EXECUTE IMMEDIATE querystr INTO result;
return result;
end;
END ;
/
You need to change the type of your variables, considering that
"The return data type is RAW if the measure column is RAW; otherwise the return value is VARCHAR2" (documentation)
EXECUTE needs a VARCHAR2: "It must be of type CHAR or VARCHAR2, not NCHAR or NVARCHAR2"
So:
declare
querystr varchar2(2000) ;
result VARCHAR2(32767);
begin
...
i have a table that the content of it:
ID A B
--- --- ----
1 123 &%df
2 587 364
A function was written to find invalid number(below script)
CREATE OR REPLACE FUNCTION is_number RETURN number IS
A_var number(15);
B_var number(15);
BEGIN
for u in (select id,
A,
B,
from TABLE_NAME) LOOP
BEGIN
select
to_number(u.A),
to_number(u.B),
into A_var , B_var
from dual;
EXCEPTION
WHEN others THEN
update TABLE_NAME set ?????? = null where id = u.id;
END;
END LOOP;
return -1;
END is_number;
the top script I want to replace ?????? to name of column as invalid number that in this example name of column is B
after excution top script,content of table is:
ID A B
--- --- ----
1 123
2 587 364
What if number conversion errors will be in both columns?
Try this:
create or replace function is_number return number is
a_var number(15);
b_var number(15);
function custom_to_number(v varchar2) return number is
result number;
begin
result:=to_number(v);
return result;
exception when others then
if(sqlcode = -6502) then
return null;
end if;
raise;
end;
begin
for u in (select id
,a
,b
from table_name)
loop
a_var:=custom_to_number(u.a);
b_var:=custom_to_number(u.b);
if((u.a is not null and a_var is null) or (u.b is not null and b_var is null)) then
update table_name
set a = case when a_var is null then null else a end
,b = case when b_var is null then null else b end
where id = u.id;
end if;
end loop;
return -1;
end is_number;
If your Intend is to replace the columns which contains alphanuneric data to NULL in the table, then you could use a Trigger to acheive this.
CREATE OR REPLACE TRIGGER trigger_Name BEFORE INSERT OR UPDATE OF
A_var, B_var ON TABLE_NAME
FOR EACH ROW
BEGIN
IF NOT((regexp_like (:NEW.A_var,'^[[:digit:]]+$'))) THEN
:NEW.A_var := NULL;
END IF;
IF NOT((regexp_like (:NEW.B_var,'^[[:digit:]]+$'))) THEN
:NEW.B_var := NULL;
END IF;
INSERT INTO TABLE_NAME(A_var, B_var) Values(:NEW.A_var, :NEW.B_var);
END;