MariaDB create stored procedure syntax error - mariadb

I feel like such a noob for asking this, but I can't for the life of me figure this one out. I'm trying to create a stored procedure here:
create or replace procedure add_cart(#user_id int, #product_id int, #quantity int)
begin
declare cart_id int;
start transaction;
select id into cart_id from carts where user_id = #user_id;
if cart_id is null then
insert into carts (user_id, updated_at, inserted_at) values (#user_id, now(), now());
select id into cart_id from carts where user_id = #user_id;
end if;
insert into cart_products (cart_id, product_id, quantity) values (cart_id, #product_id, #quantity);
commit;
end
But I keep getting this SyntaxError:
[2022-06-14 10:29:29] [42000][1064] (conn=12) 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 '#user_id int, #product_id int, #quantity int)
[2022-06-14 10:29:29] [42000][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 '#user_id int, #product_id int, #quantity int)
[2022-06-14 10:29:29] begin
[2022-06-14 10:29:29] declare cart_id int;
[2022-06-14 10:29:29] ...' at line 1
MariaDB version 10.6.0 if that's relevant.
Thanks :)

Nvm, got it. It was the # signs :)

Related

.sql database import not working. (stored procedure error)

I am new to MySQL.
I want to import the database from .sql file.
Tables are imported successfully.
but it gives the below error regarding procedures :
CREATE DEFINER=`dev`#`%` PROCEDURE `sp_PlaceBet`(
IN `pLogInId` INT,
IN `pUserId` INT,
IN `pParantId` INT,
IN `pMatchId` INT,
IN `pSelectionId` INT,
IN `pStack` INT,
IN `pMarketId` VARCHAR(100),
IN `pselectionName` VARCHAR(100),
IN `pMstDate` DATETIME,
IN `pOdds` DECIMAL(10, 2),
IN `pP_L` DECIMAL(10, 2),
IN `pisBack` INT,
IN `pIsMatched` INT,
IN `pNarration` VARCHAR(200),
IN `pdeviceInfo` VARCHAR(100),
IN `pIP_ADDESSS` VARCHAR(100),
IN `pInPlayStack` INT,
IN `pIsApp` INT,
IN `pType` VARCHAR(100)
)
BEGIN
DECLARE LID INTEGER;
DECLARE lCtr integer;
DECLARE resultV INT;
DECLARE retMess VARCHAR(500);
DECLARE checkBal decimal(50, 2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
set resultV = -1;
GET STACKED DIAGNOSTICS CONDITION 1 #sqlstate = RETURNED_SQLSTATE, #errno = MYSQL_ERRNO, #text = MESSAGE_TEXT;
SET retMess = CONCAT("ERROR ", #errno, " (", #sqlstate, "): ", #text);
ROLLBACK;
[...]
MySQL said: Documentation
#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 'STACKED DIAGNOSTICS CONDITION 1 #sqlstate = RETURNED_SQLSTATE, #errno = MYSQL...' at line 31
Please help me to solve this error.
Thanks!
The problem is that you are using mariadb, not mysql. If you check out the error message, it tells you to fefer to the mariadb manual.
Mariadb's get diagnostics statement does not have stacked option, so you must remove it if you want to use the code in a mariadb environment or you need to migrate to a proper mysql server.

Procedure run details for a day

Please let me know if you can provide the detail of “number of times” a procedure has been called for that particular day, for the all the valid procedures.
You can use your own logging technic. For example first you can create a table under the same schema of your desired procedure. Then after begin statement end before end statement in that invoked procedure, you can insert logs to newly created log table of yours.
CREATE TABLE SCHEMA.LOGTABLE
(
DATECOLUMN DATE DEFAULT SYSTIMESTAMP,
PROCNAME VARCHAR2 (200 CHAR),
TABLENAME VARCHAR2 (200 CHAR),
MESSAGE VARCHAR2 (1000 CHAR),
LOGSEQUENCE NUMBER
);
CREATE OR REPLACE PROCEDURE SCHEMA.PROCNAME IS
BEGIN
INSERT INTO SCHAME.LOGTABLE(DATECOLUMN,
PROCNAME,
TABLENAME,
MESSAGE,
LOGSEQUENCE)
VALUES (SYSTIMESTAMP,
'SCHEMA.PROCNAME',
'SCHEMA.TABLENAME',
'Proc STARTED',
NULL,
SCHEMA.SEQ_SISTEM_LOG.NEXTVAL);
COMMIT;
.....
INSERT INTO SCHAME.LOGTABLE(DATECOLUMN,
PROCNAME,
TABLENAME,
MESSAGE,
LOGSEQUENCE)
VALUES (SYSTIMESTAMP,
'SCHEMA.PROCNAME',
'SCHEMA.TABLENAME',
'Proc ENDED',
NULL,
SCHEMA.SEQ_SISTEM_LOG.NEXTVAL);
COMMIT;
END;

Insert procedure - check if foreign key exists in primary table

I have the following procedure (insert_mapping):
create or replace procedure p_insert_mapping
(header_id in number,
position in number,
xml_mapping in varchar2,
id out number,
result_code out number
)
is
l_id number;
begin
-- check for errors
if header_id not in (select log_push_readouts_headers.id from log_push_readouts_headers) then
result_code := 9302;
raise_application_error(-RESULT_CODE, 'Foreign key constraint violated for headers');
end if;
-- if there are no errors, do insert
if result_code is null then
-- fetch sequence number
id := mapping_seq.nextval;
insert into log_push_readouts_mappings
(id, position, xml_mapping)
values
(id, position, xml_mapping);
end if;
commit;
end;
In the following line:
if header_id not in (select log_push_readouts_headers.id from log_push_readouts_headers) then
I need to check if foreign key exists in main table.
How to do that?
Could someone give me an example on how to check if foreign key is in a table with primary key?
I am getting the following error: Compilation errors for PROCEDURE
AMM_MDM.P_INSERT_MAPPING
Error: PLS-00405: subquery not allowed in this context
Line: 12
Text: if header_id not in (select log_push_readouts_headers.id from log_push_readouts_headers) then
Error: PL/SQL: Statement ignored
Line: 12
Text: if header_id not in (select log_push_readouts_headers.id from log_push_readouts_headers) then
regarding the compilation error, please refer
Using a subquery within PLSQL conditional logic; error PLS-00405
and for checking foreign key constraint on a column of a table, we can query from all_constrainsts, where CONSTRAINT_TYPE can be checked
doc ref: https://docs.oracle.com/cd/B14117_01/server.101/b10755/statviews_1037.htm#i1576022
What you can do is fetch the matching count of sub-query into a number type variable and then use that in if-else statement to compute the flow of your code
select count(1) into <some variable> from log_push_readouts_headers a where log_push_readouts_headers.id = header_id
Now check this count against your desired value in if-else statement.

Does Oracle support non-scalar cursor parameter?

This is a question about Oracle PL/SQL.
I have a procedure in which the exact WHERE clause is not known until the run time:
DECLARE
CURSOR my_cursor is
SELECT ...
FROM ...
WHERE terms in (
(SELECT future_term2 FROM term_table), -- whether this element should be included is conditional
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
);
BEGIN
(the processing)
END;
/
What the (SELECT ... FROM term_table) query returns is a 4-character string.
For a solution to this, I am thinking of using a parameterized cursor:
DECLARE
target_terms SOME_DATATYPE;
CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS
SELECT ...
FROM ...
WHERE terms in my_cursor.pi_terms;
BEGIN
target_terms := CASE term_digit
WHEN '2' THEN (
(SELECT future_term2 FROM term_table),
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
) ELSE (
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
)
END;
FOR my_record IN my_cursor (target_terms) LOOP
(the processing)
END LOOP;
END;
/
The problem is what the datatype for SOME_DATATYPE should be is not known to me, nor is it known whether Oracle supports such a cursor parameter at all. If supported, is the way shown above to fabricate the value for target_terms correct? If not, how?
Hope someone who know can advise. And thanks a lot for the help.
You can certainly pass a parameter to a cursor, just like you can to a function - but only IN parameters. However, PL/SQL is a strongly typed language, so the datatype must be specified at the time of compilation.
It looks to me like what you will need to do is construct the query dynamically and then use
OPEN cursor FOR l_query;
where l_query is the constructed string. This should give you a feel for what you can do:
CREATE OR REPLACE PACKAGE return_id_sal
AUTHID DEFINER
IS
TYPE employee_rt IS RECORD
(
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR;
END return_id_sal;
/
CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR
IS
l_return SYS_REFCURSOR;
BEGIN
OPEN l_return FOR
'SELECT employee_id, salary FROM employees ' || append_to_from_in;
RETURN l_return;
END allrows_by;
END return_id_sal;
/
DECLARE
l_cursor SYS_REFCURSOR;
l_row return_id_sal.employee_rt;
BEGIN
l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');
LOOP
FETCH l_cursor INTO l_row;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
END;
/
You will need to take precautions against SQL injection with this sort of code. Certainly a user should never be able to pass SQL text directly to such a function!
You can use also some built-in VARRAY SQL types like SYS.ODCIVARCHAR2LIST or create your own :
CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
AS VARRAY(32767) OF VARCHAR2(4000);
Then you can use it with SELECT COLUMN_VALUE FROM TABLE(COLLECTION) statement in your cursor:
DECLARE
l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST
CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS
SELECT your_column
FROM your_table
WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
select term
bulk collect into l_terms
from (
select 'term1' term from dual
union all
select 'term2' term from dual
);
FOR my_record IN my_cursor (l_terms) LOOP
--process data from your cursor...
END LOOP;
END;

How to use variable of declare at the where of select?

How to use variable of declare at the where of select ?
CREATE TABLE student (
id smallint PRIMARY KEY,
first_name VARCHAR(80) NOT NULL,
last_name VARCHAR(80) NOT NULL);
insert into student VALUES(10,'AA','A01');
insert into student VALUES(30,'BB','B01');
---MSSQL OK
declare #v_first varchar(10);
set #v_first='AA';
select * from student where first_name=#v_first;
---ORACLE --ERROR
declare v_first varchar2(10);
BEGIN
v_first :='AA';
select * from student where first_name= v_first;
END;
---=> MESSAGE
ORA-06550: line 4 , column 3 :
PLS-00428: 在此 SELECT 敘述句中預期會出現一個 INTO 子句
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The example you gave for MSSQL is a different table, but assuming DEPT_ID from USER_LIST is a NUMBER too... SQL will automatically convert the string to compare...
You need to cast the id to a number. Is there a reason you are declaring a varchar variable right before comparing it against a number?
declare v_id varchar2(2);
BEGIN
v_id :='30';
select * from student where id= TO_NUMBER(v_id);
END;
or change the declare and the assignment...
declare v_id NUMBER;
BEGIN
v_id :=30;
select * from student where id= v_id;
END;
basically, what the link I added in the comments below said.. from user tvm.. "You cannot use SELECT without INTO clause in PL/SQL. The output of the SELECT must be stored somewhere. Eg. table or variable or perhaps a record. See example below how to store result of the SELECT statement into record."
DECLARE
v_id number;
v_result Student%ROWTYPE;
BEGIN
v_id := 30;
SELECT * INTO v_result
FROM Student
WHERE id = v_id;
END;
Then you need to do something with v_result... other option shown is to call straight SQL - all depends on how you call and consume the data..

Resources