Syntax error in MariaDB Stored Procedure With Parameter - mariadb

Im trying to create a procedure for a railway database on phpmyadmin. In which the train number, train date, and category is read from the passenger. On the basis of the values provided by the passenger, corresponding record is retrieved from the Train_Status table. If the desired category is AC, then total number of AC seats and number of booked AC seats are compared in order to find whether ticket can be booked or not. Similarly, it can be checked for the general category. If ticket can be booked, then passenger details are read and stored in the Passenger table.
I have scratched my head on the procdure syntax but it is still giving an error. Tried changing syntax, removing the check condtion from variables but nothing seems to work.
The error it gives is
"#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near 'CHECK (train_number>=1 AND train_number<=5); DECLARE t_date
DATE; DECLA...' at line 6"
The mariadb version is 10.4.25
Here it is what I created
DELIMITER $$
CREATE PROCEDURE Booking (t_num int(1), t_date DATE, category varchar(10) )
BEGIN
DECLARE t_num int(1) CHECK (train_number>=1 AND train_number<=5);
DECLARE t_date DATE;
DECLARE category ENUM('AC', 'General');
DECLARE status ENUM('Confirmed', 'Waiting');
DECLARE getTrain CURSOR FOR
SELECT * FROM Train_Status
WHERE train_number = t_num AND train_date = t_date;
DECLARE trec Train_Status % ROWTYPE;
DBMS_OUTPUT.PUT_LINE('READING VALUES');
t_num := &t_num;
t_date := '&t_date';
category := '&category';
OPEN getTrain;
LOOP
FETCH FROM getTrain INTO trec;
EXIT WHEN getTrain % NOTFOUND;
IF(category = 'AC') THEN
IF(trec.t_acseats - trec.b_acseats) > 0 THEN
status := 'Confirmed';
DBMS_OUTPUT.PUT_LINE('Seat Confirmed');
ELSIF(trec.t_acseats - trec.b_acseats) > -2 THEN
status := 'Waiting';
DBMS_OUTPUT.PUT_LINE('Seat Waiting');
ELSE
DBMS_OUTPUT.PUT_LINE('Seat Not Available');
EXIT;
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
UPDATE Train_Status SET b_acseats = b_acseats + 1 WHERE
TrainNumber = t_num and TrainDate = t_date;
END IF;
ELSIF(category = 'General') THEN
IF(trec.t_genseats - trec.b_genseats) > 0 THEN
status := 'Confirmed';
DBMS_OUTPUT.PUT_LINE('Seat Confirmed');
ELSIF(trec.t_genseats - trec.b_genseats) > -2 THEN
status := 'Waiting';
DBMS_OUTPUT.PUT_LINE('Seat Waiting');
ELSE
DBMS_OUTPUT.PUT_LINE('Seat Not Available');
EXIT;
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
UPDATE Train_Status SET b_genseats = b_genseats + 1
WHERE TrainNumber = t_num and TrainDate = t_date;
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('Invalid Category');
END IF;
IF status = 'Confirmed' OR status = 'Waiting' THEN
INSERT INTO Passengers
VALUES ('&T_ID', t_num, t_date, '&Name', &Age, '&Sex', '&Address', status, category);
END IF;
END LOOP;
CLOSE getTrain;
END $$
DELIMITER ;

Check can't be used while declaring the variables. Only name and data type should be there.
Check cursor syntax from MariaDB documentation.
These two things will solve your 70% problems. Rest you can figure out.

Related

PL/SQL: I get expression 'I' cannot be used as an assignment target

My code:
create table info(str varchar2(30));
declare
cursor c(job emp_ast.job_id%type, dep emp_ast.department_id%type) is select employee_id
from emp_ast
where job_id=job and department_id=dep;
type t_job is table of emp_ast.job_id%type;
t t_job:=t_job();
emp emp_ast.employee_id%type;
i number(3);
begin
select job_id
bulk collect into t
from emp_ast;
for i in 10..270 loop
for j in 1..t.count loop
open c(i, t(j));
loop
fetch c into emp;
insert into info
values (i||' '||t(j)||' '||emp);
exit when c%notfound;
end loop;
i:=i+10;
end loop;
end loop;
end;
/
I get "expression 'I' cannot be used as an assignment target", reffering to the line where I increment i by 10. I am trying to save the department_id, employee_id and job_id as a string in a table for each department and each job.
At the point where you get that message, i refers to the loop control variable i defined in the line for i in 10..270 loop, not the int(3) variable defined earlier. In PL/SQL a loop definition defines a variable which is only accessible inside the loop, and which you cannot alter. I suggest you change the name of one or the other to make them unique.
EDIT
PL/SQL doesn't provide a way to step by more than 1 in a computed FOR loop. Instead, you will need to compute the desired department number value within the loop:
DECLARE
CURSOR c(job EMP_AST.JOB_ID%TYPE,
dep EMP_AST.DEPARTMENT_ID%TYPE)
IS SELECT EMPLOYEE_ID
FROM EMP_AST
WHERE JOB_ID = job AND
DEPARTMENT_ID = dep;
TYPE t_job IS TABLE OF EMP_AST.JOB_ID%TYPE;
t t_job := t_job();
emp EMP_AST.EMPLOYEE_ID%TYPE;
nDepartment NUMBER;
BEGIN
SELECT job_id
BULK COLLECT INTO t
FROM EMP_AST;
FOR i IN 1..27 LOOP
nDepartment := i * 10;
FOR j IN 1..t.COUNT LOOP
OPEN c(t(j), nDepartment);
LOOP
FETCH c INTO emp;
INSERT INTO info
VALUES (nDepartment || ' ' || t(j) || ' ' || emp);
EXIT WHEN c%notfound;
END LOOP; -- cursor c
CLOSE c;
END LOOP; -- j
END LOOP; -- i
END;
/
Note that in the code above the nDepartment value is computed within the i loop, which now increments from 1 to 27 instead of going from 10 to 270.

PL/SQL switch if statement

How can I change this nested IF statement to a compound IF statements, I know it is pretty much the same but I do not know how to implement that with my code.
SET VERIFY OFF
DECLARE
v_idno donornew.idno%TYPE :=&input_idno;
v_yrgoal donornew.yrgoal%TYPE;
v_newgoal donornew.yrgoal%TYPE;
v_state donornew.state%TYPE;
v_city donornew.city%TYPE;
BEGIN
SELECT yrgoal, state, city INTO v_yrgoal, v_state, v_city
FROM donornew
WHERE idno = v_idno;
IF v_state = 'MA' AND ( v_yrgoal < 400 or v_city = 'Fall River') THEN
v_newgoal := v_yrgoal * 2.5;
ELSE
v_newgoal := v_yrgoal * 1.3;
END IF;
UPDATE donornew
SET yrgoal = v_newgoal
WHERE idno = v_idno;
COMMIT;
END;
/
SET VERIFY ON
Hello bascically for thsi purpose i will suggest you to go with purely SQL logic rather than PLSQL approach. Merge is the perfect example to resolve your issues.
-- Approach is to use SQL approach rather then using PLSQL approach.
MERGE INTO donornew D USING
(SELECT yrgoal,
state,
city,
idno,
CASE
WHEN state = 'MA'
AND (yrgoal < 400
OR city = 'Fall River')
THEN yrgoal * 2.5
ELSE yrgoal * 1.3
END newgoal
FROM donornew
WHERE idno = v_idno -- Input IDNO
)A ON (d.idno = a.idno )
WHEN MATCHED THEN
UPDATE SET yrgoal = a.newgoal;
Let me know if this helps.

ORA-21700 on SELECT FROM package-user-defined TABLE

I'm creating an Oracle package (MyPackage) where I have a public custom type table (ObjDataCollection) of custom type records (ObjData), which will be used as IN parameter for one of the Package functions (Calculate):
CREATE OR REPLACE PACKAGE MyPackage AS
TYPE ObjData IS RECORD (
t date NOT NULL := DATE '0001-01-01',
v number(9, 4)
);
TYPE ObjDataCollection IS TABLE
OF ObjData;
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number;
END MyPackage;
CREATE OR REPLACE PACKAGE BODY MyPackage AS
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number IS
res number(9, 4) := 0;
dateStart date;
dsv ObjData;
CURSOR q1 (dt date) IS
SELECT * FROM TABLE(DataSource) --Throws ORA-21700: Object does not exist or is marked for delete oracle.
WHERE t >= dt
ORDER BY t;
BEGIN
-- some irrelevant code
dateStart := DATE '2015-01-01';
OPEN q1(dateStart);
LOOP FETCH q1 INTO dsv;
EXIT WHEN q1%NOTFOUND;
res := res + dsv.v;
-- some irrelevant code
END LOOP;
CLOSE q1;
-- some irrelevant code
return res;
END Calculate;
END MyPackage;
I debbuged my code and I get the error on the second line of the cursor (marked in code):
ORA-21700: Object does not exist or is marked for delete oracle.
I'm using this data to execute my package:
CREATE TABLE TestTable (d date DEFAULT DATE '0001-01-01', v number(9, 4));
INSERT INTO TestTable VALUES (DATE '2015-01-01', 2.1);
INSERT INTO TestTable VALUES (DATE '2015-01-08', 3.1);
INSERT INTO TestTable VALUES (DATE '2015-01-15', 4.1);
INSERT INTO TestTable VALUES (DATE '2015-01-22', 5.1);
INSERT INTO TestTable VALUES (DATE '2015-01-29', 6.1);
INSERT INTO TestTable VALUES (DATE '2015-02-05', 7.1);
And this code to run a test:
CREATE OR REPLACE PROCEDURE TestMyPackage AS
res MyPackage.ObjDataCollection;
counter number(9, 4);
BEGIN
SELECT d, v
BULK COLLECT INTO res
FROM TestTable
ORDER BY v;
counter := MyPackage.Calculate(res);
END TestMyPackage;
Why I recieve this ORA-21700 exception?
PACKAGE BODY MyPackage AS
FUNCTION Calculate(
DataSource IN ObjDataCollection
) RETURN number IS
res BINARY_FLoAT:= 0;
dateStart date;
dsv ObjData;
copy_of_DataSource ObjDataCollection;
procedure sortCollection(toSort in out ObjDataCollection)
is
type idx_coll is table of ObjData;
type sort_help is table of idx_coll index by varchar2(16 char);
v_sort sort_help;
v_temp varchar2(16);
v_result ObjDataCollection := new ObjDataCollection();
v_cnt PLS_INTEGER := 0;
begin
for i in nvl(toSort.first,1) .. nvl(toSort.last,-1) loop
v_temp := to_char(toSort(i).t,'yyyymmddhh24miss');
if v_sort.exists(v_temp) then
v_sort(v_temp).extend(1);
v_sort(v_temp)(v_sort(v_temp).count) := toSort(i);
else
v_sort(v_temp) := idx_coll(toSort(i));
end if;
end loop;
v_result.extend(toSort.count);
v_temp := v_sort.first;
while v_temp is not null loop
for i in nvl(v_sort(v_temp).first,1) .. nvl(v_sort(v_temp).last,-1) loop
v_cnt := v_cnt +1;
v_result(v_cnt) := v_sort(v_temp)(i);
end loop;
v_temp := v_sort.next(v_temp);
end loop;
toSort := v_result;
end;
BEGIN
-- some irrelevant code
copy_of_DataSource := DataSource;
dateStart := DATE '2015-01-01';
sortCollection(copy_of_DataSource);
for i in nvl(copy_of_DataSource.first,1) .. nvl(copy_of_DataSource.last,-1) loop
if copy_of_DataSource(i).t > dateStart then
res := res + copy_of_DataSource(i).v;
dbms_output.put_line(copy_of_DataSource(i).t);
end if;
end loop;
-- some irrelevant code
return res;
END Calculate;
END MyPackage;
As it was a task due to a date, I ended up fixing it by creating user-defined types and tables at schema level as suggested Arkadiusz Łukasiewicz in one of his comments. Thank you for your effort.
As is not what I wanted, I won't mark any answer as Correct.
Got the same problem and solved it by doing the following steps:
Drop package where type is defined
Drop package using that type
Compile package with type
Compile target package
I got this ORA-21700 after adding new constants in a package with types/constants. I guess there's some internal issue with dependencies but I haven't dug a lot.

Simple Procedure raise ORA-06502

There's the simplified version of my code who keep raise me ORA-06502:
declare
p_filter varchar2(300) := '2012';
p_value varchar2(300) := '12345.000';
w_new_value number(13,3) := null ;
w_count number(4) := null ;
BEGIN
SELECT count(*)
INTO w_count
FROM dual
where p_filter = p_filter;
--- more filters
if w_count != 0 then
w_new_value := p_value / w_count;
else
w_new_value := p_value;
end if;
-- do something
end;
/
Someone can give me a help?
DataBase Details
nls_language = italian
nls_territory = italy
nls_currency = �
nls_iso_currency = italy
nls_numeric_characters = ,.
nls_calendar = gregorian
nls_date_format = dd-mon-rr
nls_date_language = italian
nls_characterset = we8iso8859p15
nls_sort = west_european
nls_time_format = hh24:mi:ssxff
nls_timestamp_format = dd-mon-rr hh24:mi:ssxff
nls_time_tz_format = hh24:mi:ssxff tzr
nls_timestamp_tz_format = dd-mon-rr hh24:mi:ssxff tzr
nls_dual_currency = �
nls_nchar_characterset = al16utf16
nls_comp = binary
nls_length_semantics = byte
nls_nchar_conv_excp = false
First, this is always going return a value of 1.
SELECT count(*)
INTO w_count
FROM dual
It doesn't matter what the qualifier is.
Lastly, I just ran your simplified code example in Oracle 11R2 and it didn't throw an exception.
I added the following statement in place of your "do something" comment:
dbms_output.put_line('w_new_value: ' || w_new_value || '. w_count: ' || w_count);
The result was:
w_new_value: 12345. w_count: 1
So, I think you've simplified your example into oblivion. You need to provide something that actually shows the error.
Good luck.
I found myself the ansewer and i think is useful for other know.
The real problem of the script for my DB is the language.
The italian "version" of Oracle accept , instead of the . for translate the VARCHAR2 into NUMBER unlike the most of other country.
For make the code running well the solution is
w_new_value := replace(p_value,'.',',') / w_count;
This trick finally allows the DB use my VARCHAR2 param like a NUMBER

PL/SQL update based on flag

I have a table "flags" containing flags with "name" and "value" where "name" is the name of the flag and "value" is either 'T' or 'F'
I would like to update a table based on a flag with name 'enable_feature' in the following manner:
BEGIN;
IF ((SELECT flags.value FROM flags WHERE flags.name = 'enable_feature') = 'T')
UPDATE... SET...;
ELSE
UPDATE... SET...;
END IF;
END;
My trouble seems to be in the IF statement. Specifically, i get the following error:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the
following:
( - + case mod new not null continue avg count current
exists max min prior sql stddev sum variance execute forall merge
time timestamp interval date pipe
How do I modify this statement such that I can perform an UPDATE/SET statement based on the value of 'enable_feature' (The UPDATE/SET statement is on a different table)
DECLARE
v flags.value%type;
BEGIN
SELECT flags.value into v FROM flags WHERE flags.name = 'enable_feature';
IF v = 'T' THEN
UPDATE... SET...;
ELSE
UPDATE... SET...;
END IF;
END;

Resources