simple question here, I am writing a function, but I was having trouble setting up my first if statement, my attempt is below, but I keep getting "Expression can not be used as an assignment target" error on the lines "Type := CE;" and "Type :=UG;" Im sure there is a quick fix to this...... anyone know?
CREATE OR REPLACE FUNCTION SCHEMA1."FUNCTION1" ( Id IN VARCHAR2,
term IN VARCHAR2,
Type IN VARCHAR2 default NULL )
RETURN VARCHAR2 IS
BEGIN
IF Type IS NULL
THEN
IF SUBSTR(term,5,6) = 'Q'
THEN
Type := 'CE';
ELSE
Type := 'UG';
END IF;
END IF;
........
Declare a holding variable for use within the function?
CREATE OR REPLACE FUNCTION SCHEMA1."FUNCTION1" ( Id IN VARCHAR2,
term IN VARCHAR2,
Type IN VARCHAR2 default NULL )
RETURN
VARCHAR2
IS
iType VARCHAR2;
BEGIN
iType := Type;
IF iType IS NULL
THEN
IF SUBSTR(term,5,6) = 'Q'
THEN
iType := 'CE';
ELSE
iType := 'UG';
END IF;
END IF;
........
Looks to me like you're passing 'Type' in as an argument and then trying to assign to it. Is your intent to RETURN 'CE'/'UG' based on Term? If so, introduce a new variable or change Type := to RETURN.
Related
I got the object T_CONTRIBUYENTE, it has the attribute HABILITADO and the member function P_VERIFICAR_HABILITACION. The function is supposed to assign 'S' to self.HABILITADO, but I don't know if that's possible. When I run the code above, I get the error
PLS-00363 "The expression 'SELF.HABILITADO' can't be used as an assignment target.
I think is more of a conceptual problem, and I don't have it very clear. I googled but couldn't find anything helpful.
CREATE OR REPLACE TYPE T_CONTRIBUYENTE AS OBJECT
(RUC VARCHAR2(11),
NOMBRE VARCHAR2(50),
APELLIDO_RAZON VARCHAR2(50),
TIPO_CONTRIBUYENTE VARCHAR2(1),
HABILITADO VARCHAR2(1),
FECHA_VALIDEZ DATE,
MEMBER FUNCTION P_VERIFICAR_HABILITACION RETURN VARCHAR2,
STATIC FUNCTION F_OBTENER_CONTRIBUYENTE(RUC VARCHAR2) RETURN T_CONTRIBUYENTE);
/
CREATE OR REPLACE TYPE BODY T_CONTRIBUYENTE IS
MEMBER FUNCTION P_VERIFICAR_HABILITACION RETURN VARCHAR2 IS
CURSOR C_ULTPAGO IS
SELECT MAX(p.fecha_pago)
FROM PAGOS p JOIN DECLARACION d ON p.id=d.id
WHERE d.RUC = SELF.RUC;
FECHA_PAGO DATE;
BEGIN
OPEN C_ULTPAGO;
FETCH C_ULTPAGO INTO FECHA_PAGO;
CLOSE C_ULTPAGO;
IF(MONTHS_BETWEEN(SYSDATE, FECHA_PAGO) <=1) THEN
SELF.HABILITADO := 'S';
ELSE
SELF.HABILITADO := 'N';
END IF;
END;
END;
When we're just reading the attributes of the SELF object we can rely on the implicit parameter for the function. However, to modify the object we need to explicitly define the parameter. So you need to change the signature of the member function to look like this:
MEMBER FUNCTION P_VERIFICAR_HABILITACION (SELF IN OUT NOCOPY T_CONTRIBUYENTE) RETURN VARCHAR2
Incidentally, your function doesn't actually return anything, so it will fail at runtime. If you don't want it to return a value then you should change it to be a MEMBER PROCEDURE.
I am trying to execute the function, but :
5/5 PLS-00103: begin function pragma procedure subtype type
current
cursor delete.
How can I repair it ?
create or replace function is_valid_value(resourceToCheck in varchar2,columnToCheck in varchar2,valueToCheck in varchar2)
return varchar2 is
v_value valid_values.resourceName%type;
declare
v_resource resourceToCheck;
v_name columnToCheck;
v_value valueToCheck ;
begin
begin
Select resourceName,columnName,validValue into v_resource,v_name,v_value
from valid_values
where
resourceName =resourceToCheck
AND columnName = columnToCheck
AND validvalue = valueToCheck
AND
upper(resourceName) = upper (valuetoCheck);
exception
when no_data_found then
return 0;
end;
return 1;
end is_valid_value ;
It seems you have several syntax errors in the routine:
-- function with 3 parameters
create or replace function is_valid_value(resourceToCheck in varchar2,
columnToCheck in varchar2,
valueToCheck in varchar2)
-- returns varchar2
return varchar2
is
-- uses 3 local variables; please, note their types
v_resource valid_values.resourceName%type;
v_name valid_values.columnName%type;
v_value valid_values.validValue%type;
begin
-- if we have a single record
select resourceName,
columnName,
validValue
into v_resource,
v_name,
v_value
from valid_values
where resourceName = resourceToCheck
and columnName = columnToCheck
and validvalue = valueToCheck
and upper(resourceName) = upper(valuetoCheck);
-- we return '1' (please, remember the declaration "return varchar2")
return '1';
exception
-- When we have no records
when no_data_found then
-- we return '0' (again, we return VarChar2)
return '0';
end is_valid_value;
You don't actually need the query to retrieve values just to indicate if there is a record or not. The following query seems to satisfy the requirement and be much simpler.
This way you avoid an EXCEPTION handler; neither return value is actually an exception so this seems more 'correct'.
I would also suggest using Y/N as the return if you want a VARCHAR2. Use 1/0 if you want to use a NUMBER. Mixing them could be confusing later for maintenance.
CREATE OR REPLACE FUNCTION is_valid_value(resourcetocheck IN VARCHAR2
, columntocheck IN VARCHAR2
, valuetocheck IN VARCHAR2)
RETURN VARCHAR2
IS
func_result VARCHAR2(1);
BEGIN
-- Indicate if it is a valid result
SELECT rec_exist
INTO func_result
FROM (SELECT '1' as rec_exist
FROM valid_values
WHERE resourcename = resourcetocheck
AND columnname = columntocheck
AND validvalue = valuetocheck
AND UPPER(resourcename) = UPPER(valuetocheck)
UNION ALL
SELECT '0' FROM dual)
WHERE rec_exist = 'Y' OR rownum = 1;
-- we return '1' (please, remember - VarChar2)
RETURN func_result;
END is_valid_value;
When i try to implement the function to find if rows contain a string.
The function always return 0.
This is my function
member function containsText (pString1 varchar2, pString2 varchar2)return integer is
checked integer;
begin
if INSTR(pString2,pString1)=0 then checked := 0;
else checked := 1 ;
end if;
return checked;
end containsText;
i implement the function like below,
containsText (table_name.column_name, 'some_string_here');
it returns 0.
2 i try to find out why it doesn't work by using the code below,
containsText('abcdefg','fg');
it returns 0 as well.
i try instr method alone, it works
instr('abcdefg','fg');
it returns 6.
i use instr in query to implement my original idea
select instr(table_name.column_name,'Great') from table_name
it works. How could i make this function working as my expect?
Try
member function containsText (pString1 varchar2, pString2 varchar2)return integer is
checked integer;
begin
if INSTR(pString1, pString2)=0 then checked := 0;
else checked := 1 ;
end if;
return checked;
end containsText;
You change in INSTR(pString1, pString2)=0
You have the arguments to INSTR reversed. Also you have a MEMBER function but do not appear to be using any features that would require this. You could use:
Oracle Setup:
CREATE TYPE test_obj AS OBJECT(
value VARCHAR2(20),
MEMBER FUNCTION checkText(
self IN OUT test_obj,
match IN VARCHAR2
) RETURN NUMBER
);
/
CREATE TYPE BODY test_obj IS
MEMBER FUNCTION checkText(
self IN OUT test_obj,
match IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
RETURN LEAST( INSTR( self.value, match ), 1 );
END;
END;
/
Testing:
DECLARE
v_test test_obj := test_obj( 'abcdefgh' );
BEGIN
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'gh' ) );
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'i' ) );
END;
/
Outputs:
1
0
db<>fiddle here
You could also write it without the SELF argument and taking two strings (as you've done in the question) but there does not seem to be much point of making this a MEMBER function of a type and it could just be a global stored-function or a STATIC function of the type.
CREATE TYPE test_obj AS OBJECT(
unused_value VARCHAR2(20),
MEMBER FUNCTION checkText( -- could be STATIC FUNCTION
value IN VARCHAR2,
match IN VARCHAR2
) RETURN NUMBER
);
/
CREATE TYPE BODY test_obj IS
MEMBER FUNCTION checkText( -- could be STATIC FUNCTION
value IN VARCHAR2,
match IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
IF INSTR( value, match ) = 0 THEN
RETURN 0;
ELSE
RETURN 1;
END IF;
END;
END;
/
Then:
DECLARE
v_test test_obj := test_obj( 'xyz' );
BEGIN
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'abcdefgh', 'gh' ) );
DBMS_OUTPUT.PUT_LINE( v_test.checkText( 'abcdefgh', 'x' ) );
END;
/
Outputs:
1
0
db<>fiddle here
I am using oracle SQL developper.
I am trying to create a function that will accept two parameters (first and last name) and return them as one variable, with the last name showing up first. Here is my function.
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
BEGIN
DECLARE varFullName VARCHAR2;
DEFINE varFullName := CONCAT(varLastName,' ' ,varFirstName);
RETURN varFullName;
END LASTNAMEFIRST;
I am receiving an error on the semicolon at 'end lastnamefirst' "syntax error"
I keep trying to change small things and that same error just shows up in different places whenever I change things. What am I doing wrong?
Wrong syntax. Should be
SQL> create or replace function lastnamefirst
2 (varfirstname in varchar2,
3 varlastname in varchar2)
4 return varchar2
5 as
6 begin
7 return varlastname||' '||varfirstname;
8 end;
9 /
Function created.
SQL> select lastnamefirst('Little', 'Foot') result from dual;
RESULT
------------------------------
Foot Little
SQL>
What's wrong with your code?
you don't DECLARE within the body; if you do, there's no DECLARE keyword at all, and datatype requires length (such as VARCHAR2(30))
CONCAT accepts only two arguments; use a concatenation operator, double pipe || instead
there's no DEFINE in PL/SQL
I would expect the Oracle syntax to look more like:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST (
in_FirstName IN VARCHAR2,
in_LastName IN VARCHAR2
)
RETURN VARCHAR2 AS
v_FullName varchar2(4000);
BEGIN
v_FullName := in_LastName || ' ' || in_FirstName;
RETURN v_FullName;
END; -- LASTNAMEFIRST;
This can of course be simplified (say by not using a local variable), but it follows the logic of your code.
Using DECLARE where you have is essentially starting a new code block, which is leading to the error you see. In your code, the DECLAREisn't necessary if you move the variable declaration prior to the BEGIN. DEFINE is also invalid. Something like this should work:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
varFullName VARCHAR2(100);
BEGIN
varFullName := varLastName || ' ' || varFirstName;
RETURN varFullName;
END LASTNAMEFIRST;
This could be simplified further by removing the variable declaration completely:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
BEGIN
RETURN varLastName || ' ' || varFirstName;
END LASTNAMEFIRST;
I have a package as such:
CREATE OR REPLACE PACKAGE someschema.somepackage
AS
TYPE t_str_array IS TABLE OF VARCHAR2 (500)
INDEX BY BINARY_INTEGER;
PROCEDURE some_procedure_p (in_first IN NUMBER,
in_second IN VARCHAR2,
in_third IN t_str_array,
in_fourth IN date,
in_fifth IN date,
out_sixth_cur OUT t_some_ref);
END;
/
CREATE OR REPLACE PACKAGE BODY someschema.somepackage
AS
PROCEDURE some_procedure_p (in_first IN NUMBER,
in_second IN VARCHAR2,
in_third IN t_str_array,
in_fourth IN date,
in_fifth IN date,
out_sixth_cur OUT t_some_ref);
IS
BEGIN
FOR i IN in_third.FIRST .. in_third.LAST
LOOP
... do something
END LOOP COMMIT;
OPEN out_sixth_cur FOR
SELECT ... something;
END;
END somepackage;
How do I execute this procedure in toad? So far I've tried:
Right click on the procedure, click execute package, call code is generated automatically:
DECLARE
IN_FIRST NUMBER;
IN_SECOND VARCHAR2(32767);
IN_THIRD someschema.somepackage.t_str_array;
IN_FOURTH DATE;
IN_FIFTH DATE;
OUT_SIXTH_CUR someschema.somepackage.t_some_ref;
BEGIN
IN_FIRST := NULL;
IN_SECOND:= NULL;
IN_FOURTH := NULL;
IN_FIFTH := NULL;
OUT_SIXTH_CUR := NULL;
someschema.somepackage.some_procedure_p ( IN_FIRST, IN_SECOND, IN_THIRD, IN_FOURTH, IN_FIFTH, OUT_SIXTH_CUR );
:rc0_OUT_SIXTH_CUR := OUT_SIXTH_CUR;
COMMIT;
END;
I added:
IN_THIRD := t_str_array('something');
But when I ran it like this, I got the following error:
PLS-00201: identifier 'T_STR_ARRAY' must be declared
Why did I get this error if I already defined this type in the package spec?? I've tried many other ways as well but it always to complain about the type.
You need to fully qualify the type name when you do the assignment (at least to package level; the schema is redundant if it's your package anyway but doesn't hurt here), as well as when you declare it in your anonymous block:
IN_THIRD := someschema.somepackage.t_str_array('something');
There is nothing at database/schema level called t_str_array, and if you don't qualify it Oracle doesn't know it needs to come from the package. You might think it's obvious; but there's nothing stopping you having the same type name defined in more than one package, so you have to be clear and consistent.
But as you pointed out you then get
PLS-00222: no function with name 'T_STR_ARRAY' exists in this scope
... because it's a table type, not a varray, so it's instantiated when its declared. You don't need to explicitly instantiate it, which is why Toad hasn't done that for you. The documentation shows this type of collection is initialised as 'empty' rather than null.
To populate it you just assign a value, using an index position:
IN_THIRD(1) := 'something';
So the whole block would become:
DECLARE
IN_FIRST NUMBER;
IN_SECOND VARCHAR2(32767);
IN_THIRD someschema.somepackage.t_str_array;
IN_FOURTH DATE;
IN_FIFTH DATE;
OUT_SIXTH_CUR someschema.somepackage.t_some_ref;
BEGIN
IN_FIRST := NULL;
IN_SECOND:= NULL;
IN_THIRD(1) := 'something';
IN_FOURTH := NULL;
IN_FIFTH := NULL;
OUT_SIXTH_CUR := NULL;
someschema.somepackage.some_procedure_p ( IN_FIRST, IN_SECOND, IN_THIRD, IN_FOURTH, IN_FIFTH, OUT_SIXTH_CUR );
:rc0_OUT_SIXTH_CUR := OUT_SIXTH_CUR;
COMMIT;
END;
I'd suggest you consider changing the name of your type though; giving a table type a name that suggests it's an array is (clearly!) confusing. They are known as both associative arrays and index-by tables, so you could argue it's fine as it is, but I kind of assumed it was a varray based both on the name and how you were trying to use it. (I should have checked, of course).