PLS-00103 Oracle stored procedure error - sql

I am new to stored procedures.
I am trying to run stored procedure and getting these errors:
I am getting PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: begin function pragma procedure...
PLS-00103: Encountered the symbol "RETURN" when expecting one of the following: * & = - + < / > at in is mod remainder not rem then...
I have tried searching for what causes these errors and for examples similar to this, but results were not sufficient. Any clues as to why these errors are happening?
here is the code:
CREATE OR REPLACE PROCEDURE LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
) AS
BEGIN
DECLARE CNT NUMBER;
SELECT COUNT(LIST_NAME) INTO CNT FROM LISTS_MASTER WHERE LIST_NAME = LISTNAME;
IF (CNT > 0)
RETURN 1
ELSE
RETURN 0
END IF;
END LIST_ACTIONS_CHECK_ADD;
New Code:
CREATE OR REPLACE PROCEDURE LIST_ACTIONS_CHECK_ADD
(
P_LISTNAME IN VARCHAR2
)
AS
L_CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO L_CNT
FROM LISTS_MASTER
WHERE LIST_NAME = P_LISTNAME;
IF (L_CNT > 0)
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;

The skeleton of a stored procedure declaration is
CREATE OR REPLACE PROCEDURE procedure_name( <<parameters>> )
AS
<<variable declarations>>
BEGIN
<<code>>
END procedure_name;
In the code you posted,
You put the BEGIN before the variable declarations
You have an extraneous DECLARE-- you would only use that if you are declaring a PL/SQL block that doesn't involve a CREATE.
You are missing semicolons after your RETURN statements.
A procedure cannot return a value. If you want to return either a 1 or a 0, you probably want a function, not a procedure. If you need a procedure, you can declare an OUT parameter.
You are missing the THEN after the IF
It sounds like you want something like
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
)
RETURN NUMBER
AS
CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO CNT
FROM LISTS_MASTER
WHERE LIST_NAME = LISTNAME;
IF (CNT > 0)
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
Note that as a general matter, you are generally better off using some sort of naming convention to ensure that parameters and local variables do not share the name of a column. Trying to figure out whether LISTNAME is a parameter or a column name and what the difference between LIST_NAME and LISTNAME is will generally confuse future programmers. Personally, I use a p_ prefix for parameters and a l_ prefix for local variables. I would also suggested using anchored types-- lists_master.list_name%type if that is what is being passed in
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
P_LIST_NAME IN lists_master.list_name%type
)
RETURN NUMBER
AS
L_CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME)
INTO L_CNT
FROM LISTS_MASTER
WHERE LIST_NAME = P_LIST_NAME;
IF (L_CNT > 0)
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;

(Correction #1) You cannot return a value in a procedure; LIST_ACTIONS_CHECK_ADD should be dropped and declared as a function in order to return a NUMBER
(Correction #2) You need to move the declaration of CNT as follows (see below)
(Correction #3) You need semicolons on the return statements:
(Correction #4) You need a THEN after IF (CNT > 0) (see below):
DROP PROCEDURE LIST_ACTIONS_CHECK_ADD;
CREATE OR REPLACE FUNCTION LIST_ACTIONS_CHECK_ADD
(
LISTNAME IN VARCHAR2
)
RETURN NUMBER AS
CNT NUMBER;
BEGIN
SELECT COUNT(LIST_NAME) INTO CNT FROM LISTS_MASTER WHERE LIST_NAME = LISTNAME;
IF (CNT > 0) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END LIST_ACTIONS_CHECK_ADD;
This Can be executed from SQLPLUS as:
SET SERVEROUTPUT ON SIZE 100000;
DECLARE
V_RESULT NUMBER;
BEGIN
V_RESULT := LIST_ACTIONS_CHECK_ADD('X');
DBMS_OUTPUT.PUT_LINE('RESULT: ' || V_RESULT);
END;

Related

Snowflake SQL stored procedure and save value from query with dynamic SQL

I am writing a SQL stored procedure in Snowflake (language SQL NOT Javascript).
I am trying to save a count from a SELECT statement into a variable and the table name for the select statement needs to come from a variable.
Here is what I have so far but this is failing. I don't know where to put the USING or if I can even do this? I feel like I just don't have it syntactically correct yet.
create or replace procedure myprocedure(DBNAME varchar(16777216))
returns int
language sql
as
$$
DECLARE
excludeCount int;
fullyQualifiedProceduresTable varchar(16777216);
BEGIN
fullyQualifiedProceduresTable := CONCAT(DBNAME, '.INFORMATION_SCHEMA.PROCEDURES');
excludeCount := (SELECT count(*) as count from TABLE (?) WHERE PROCEDURE_OWNER = '<ROLE NAME>') USING fullyQualifiedProceduresTable ;
IF (excludeCount > 0) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
$$;
This is what I got to work using slightly different syntax for using variables.
Syntax taken from here
create or replace procedure myprocedure(DBNAME varchar(16777216))
returns int
language sql
as
$$
DECLARE
excludeCount int;
fullyQualifiedProceduresTable varchar(16777216);
BEGIN
SELECT CONCAT(:DBNAME, '.INFORMATION_SCHEMA.PROCEDURES') into :fullyQualifiedProceduresTable;
SELECT count(*) into :excludeCount from IDENTIFIER(:fullyQualifiedProceduresTable) WHERE PROCEDURE_OWNER = '<role>';
IF (excludeCount > 0) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
$$;
I am not sure why you need a procedure for this. Could you not do...
set table_name='abc';
set excludeCount=(select case when count(*)>0 then 1 else 0 end from identifier($table_name));
try this
call my_proc('bus_day');
create or replace procedure my_proc(table_name varchar)
returns table(a integer)
language sql
as
$$
declare
res RESULTSET;
query varchar default 'SELECT count(*) FROM ' || :table_name ;
begin
res := (execute immediate :query);
return table (res);
end;
$$;

Basic question about PL/SQL SELECT statement, how to declare

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 am trying to create a log_in function?Why I have error Error(3,10): PLS-00215: String length constraints must be in range (1 .. 32767)

I am trying to create a function to verify log_in by return 0(zero) if the login failed, or 1(one) if the login was successful by matching cust_id and Passwd as parametrars and I have two questions:
Why I get error bad bind p_cust_id?
How to return 0 when it fail?
.
create or replace function log_in
(
p_cust_id varchar2,
p_paswd varchar2
) return number
as p_all varchar2;
begin
select cust_id,passwd
into p_all
from customer
where cust_id=p_cust_id and passwd=p_paswd;
return 1;
end;
first of all, you are trying to select 2 column but into 1 variable. this can't be possible. check my fix below
select cust_id,passwd
into variable1, variable2
from customer
where cust_id=p_cust_id and passwd=p_paswd;
for your second requirement, you need to add below line before end.
EXCEPTION WHEN NO_DATA_FOUND THEN
return 0;
END;
EDIT
Your procedure can also be rewritten as
CREATE OR REPLACE FUNCTION LOG_IN
(
P_CUST_ID VARCHAR2,
P_PASWD VARCHAR2
) RETURN NUMBER
AS P_COUNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO P_COUNT
FROM CUSTOMER
WHERE CUST_ID=P_CUST_ID AND PASSWD=P_PASWD;
IF (P_COUNT > 0)
RETURN 1;
END IF;
RETURN 0;
END;

PLSQL -- calling function to calculate with char(1) and number variables

I'm just now teaching myself SQL and PLSQL and have haven't had too much trouble debugging the regular SQL, but I'm trying to call a PLSQL function that is throwing errors that I can't figure out from the Oracle docs and other online resources. I'm using Oracle SQL-Developer.
I've tried these but they are not helpful in this case:
How to return a record from an existing table from an Oracle PL/SQL function?
Writing a function in plsql
Oracle PLSQL function call into a second function
Can't seem to subract two numbers in a PLSQL function
I've tried writing the same function 2 different ways for practice:
Create Function Calc_Tax
(Quantity IN Number,Unit_Price IN Number,Taxable IN VarChar2)
Return Number IS amt Number;
Declare
price := Quantity * Unit_Price;
Begin
IF Taxable = 'Y' THEN
amt := price + 0.06 * price;
ELSE
amt := price;
END IF;
Return amt;
End;
-- or --
Create Or Replace Function Calc_Tax
(Quantity IN Number,Unit_Price IN Number,tax IN Sale_Item.Taxable%TYPE)
Return Number IS amt Number;
Declare
price := Quantity * Unit_Price;
Begin
IF tax = 'Y' THEN
amt := price + 0.06 * price;
ELSE
amt := price;
END IF;
Return amt;
End;
I had some trouble declaring the 'tax' parameter as a varchar2(1) so I left it just varchar2 which the docs seem to say is default for 1 space (if I read that right). Of course, I'd rather do it properly and declare the size of the varchar explicitly.
This is how I'm calling it:
DECLARE
g_last Guest.First_Name%type := 'Richard';
g_last Guest.Last_Name%type := 'Wharton';
g_id Guest.Guest_ID%type;
s_g_id Stay.Guest_ID%type;
sho_id Stay.Hotel_ID%type;
h_id Hotel.Hotel_ID%type;
h_name Hotel.Hotel_Name%type;
i_id Sale_Item.Item_ID%type;
i_name Sale_Item.Item_Name%type;
i_tax Sale_Item.Taxable%type;
cs_id Charge.Stay_ID%type;
c_date Charge.Trans_Date%type;
c_quant Charge.Quantity%type;
c_uprice Charge.Unit_Price%type;
BEGIN
SELECT H.Hotel_ID, H.Hotel_Name,C.Item_ID, Item_Name, C.Trans_Date, C.Quantity,
C.Unit_Price,Taxable INTO h_id,h_name,i_id,i_name,c_date,c_quant,c_uprice
FROM Hotel H,Charge C Where cs_id = (Select Stay_ID From Stay Where Guest_ID =
(Select Guest_ID From Guest Where First_Name='Richard' And Last_Name='Wharton'));
--WHERE id = c_id;
dbms_output.put_line
('Guest ' ||g_first || g_last || ' bought ' || i_name || ' with tax ' || Calc_Tax
(c_quant,c_uprice,i_tax));
END;
And it's throwing errors:
Error(18,1): PLS-00103: Encountered the symbol "DECLARE"
Error(43,4): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Here's the schema:
I'm just learning now, so I'm sure that any junior SQL programmers can quickly show me where I'm going wrong.
You don't use DECLARE inside a procedure or function -- use the AS keyword instead to indicate the variable declaration "block."
You also cannot put a constraint on parameters (e.g. you can have VARCHAR2 but not VARCHAR2(10) -- See Oracle docs
You also shouldn't have a semi-colon following your return statement.
Create Function Calc_Tax (Quantity IN Number, Unit_Price IN Number, Taxable IN VarChar2)
Return Number
AS
My_Variable VARCHAR2(2000);
BEGIN
-- code
END Calc_Tax;

Function to return COUNT value without COUNT

The requirements are as follows:
Create a PL/SQL function called findtotalcarmodels to return the total number of cars belonging to a particular model. The function should have a single IN parameter as model_name. You should then use an explicit cursor to count the number of cars belonging to that car model and return the final count. You must NOT use any implicit cursors, table joins, subqueries, set operators, group functions or SQL functions (such as COUNT) to create this function.
The code I have come up with so far is:
CREATE OR REPLACE Function findtotalcarmodels
(model_name IN varchar2)
RETURN NUMBER
IS
CURSOR car_count_cur IS
SELECT model_name FROM i_car;
Rec_car_details car_count_cur%ROWTYPE;
BEGIN
OPEN car_count_cur;
LOOP
FETCH car_count_cur INTO Rec_car_details;
EXIT WHEN car_count_cur%NOTFOUND;
END LOOP;
CLOSE car_count_cur;
RETURN Rec_car_details;
END;
I am getting the following errors:
Errors for FUNCTION FINDTOTALCARMODELS:
LINE/COL ERROR
15/1 PL/SQL: Statement ignored
15/8 PLS-00382: expression is of wrong type
What am I doing wrong here?
You are trying to return the cursor from the inline function, and the function is looking to return an integer.
You need an (integer) counter to increment each time you iterate through the cursor... and then you can return that. I didn't test this, but this should work:
CREATE OR REPLACE Function findtotalcarmodels
(model_name_in IN varchar2)
RETURN NUMBER
IS
DECLARE counter INTEGER := 0;
CURSOR car_count_cur IS
SELECT model_name FROM i_car WHERE model_name = model_name_in;
Rec_car_details car_count_cur%ROWTYPE;
BEGIN
OPEN car_count_cur;
LOOP
FETCH car_count_cur INTO Rec_car_details;
EXIT WHEN car_count_cur%NOTFOUND;
counter := counter + 1;
END LOOP;
CLOSE car_count_cur;
RETURN counter;
END;
CREATE OR REPLACE FUNCTION findtotalcarmodels (vc_model_name IN VARCHAR2)
RETURN NUMBER
AS
CURSOR c1
IS
SELECT *
FROM i_car
WHERE UPPER (model_name) = UPPER (vc_model_name);
cnt NUMBER;
BEGIN
cnt := 0;
FOR i IN c1 LOOP
cnt := cnt + 1;
END LOOP;
RETURN cnt;
END;
You can check in dual table such as,
SELECT findtotalcarmodels('SUV1') FROM DUAL; -- here suv1 is your modelname