I'm trying to create a stored procedure which will take a comma separated list as a value and push that into a select statement with an IN clause. I'm aware of find_in_set which works, but does have a performance overhead. I've also trialled a prepare statement but the problem remains.
My Example:
My parameter is sp1 and contains the value: 'valuex, valuey, valuez'.
BEGIN
set #sql = concat('select * from tablename WHERE assignedTo in (', sp1, ')');
PREPARE q FROM #sql;
execute q;
END
As expected, this throws an error since SQL will treat the value as column names. My question is how do I achieve: 'valuex','valuey','valuez' FROM 'valuex, valuey, valuez'?
You can use replace function:
BEGIN
set #sql = concat("select * from tablename WHERE assignedTo in ('", replace(sp1,",","','"), "')");
PREPARE q FROM #sql;
execute q;
END
An option is:
DELIMITER $$
DROP PROCEDURE IF EXISTS `sp_test`$$
CREATE PROCEDURE `sp_test`(`sp1` VARCHAR(50))
BEGIN
SET `sp1` := REPLACE(REPLACE(`sp1`, ', ', ','), ',', '\',\'');
SET #`query` := CONCAT('SELECT `column0`, `column1` FROM `tablename` WHERE `assignedTo` IN (\'', `sp1`, '\');');
PREPARE `stmt` FROM #`query`;
EXECUTE `stmt`;
DEALLOCATE PREPARE `stmt`;
END$$
DELIMITER ;
CALL `sp_test`('valuex, valuey, valuez');
-- SELECT `column0`, `column1` FROM `tablename` WHERE `assignedTo` IN ('valuex','valuey','valuez');
Related
how i can convert a row inside a mysql/mariadb trigger into an json object with new JSON features?
BEGIN
CALL my_audit_insert(tableName, id, ... JSON_OBJECT(NEW) ...);
END
Is there any possibility to get programatically columns of NEW or OLD?
First Try - Create a Statement
Idea is to get colums from system tables and get each value from NEW/OLD programatically
BEGIN
SET #s = 'SELECT NEW.? INTO #result';
PREPARE stmt FROM #s;
SET #a = 'id';
EXECUTE stmt USING #a;
CALL audit_insert(NEW.id, 'pages', JSON_ARRAY(result));
END
(1336): Dynamic SQL is not allowed in stored function or trigger
Second Idea - Select the row via PrimaryKey as JSON_Object in after-triggers
procedure spGetJson from https://stackoverflow.com/a/35957518/7080961
DROP PROCEDURE IF EXISTS `spGetJson`;
DELIMITER //
CREATE DEFINER=`root`#`%` PROCEDURE `spGetJson`(pTableName varchar(45), pId int, out pJson JSON)
begin
select group_concat(concat("'", COLUMN_NAME, "', ", COLUMN_NAME) separator ',')
into #cols
from information_schema.columns
where TABLE_NAME = pTableName and TABLE_SCHEMA = database();
set #q = concat('select json_object(', #cols, ') INTO #a from ', pTableName);
if pId is not null then
set #q = concat(#q, ' where id = ', pId);
end if;
set #q = concat(#q, ';');
prepare statement from #q;
execute statement;
deallocate prepare statement;
SET pJson = #a;
end//
DELIMITER;
After Insert Trigger:
BEGIN
CALL spGetJson('pages', NEW.id, #a);
CALL audit_insert(NEW.id, 'pages', #a);
END
same: (1336): Dynamic SQL is not allowed in stored function or trigger
Conclusion:
have to wait for this feature: https://bugs.mysql.com/bug.php?id=89366
or switch to postresql
I'm learning Functions, Procedures and Triggers and I wanted to do a easy procedure that count the rows in a table from parameters.
create procedure countRows(IN v varchar(30))
SELECT COUNT(*) FROM v;
Can someone tell me why if I do:
call countRows('sometable');
call countRows(sometable); //I tried both
It just don't work
Sorry for that newbie question.
You need dynamic sql.
Solution for returning count of any table passed as a parameter to sp
DELIMITER $$
CREATE PROCEDURE `countRows`(IN v varchar(30))
BEGIN
SET #t1 =CONCAT("SELECT COUNT(*) FROM ",V);
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
END$$
DELIMITER ;
Execution
call countRows('sometable');
Update: Solution for returning "Table x contain n row(s)" for a table passed as a parameter to sp
DELIMITER $$
CREATE PROCEDURE `countRowsEx`(IN v VARCHAR(30))
BEGIN
-- SET #t1 =CONCAT("SELECT COUNT(*) FROM ",V);
SET #t1 =CONCAT('SET #totalRows=(SELECT COUNT(*) FROM ',v, ' );');
PREPARE stmt3 FROM #t1;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
SELECT CONCAT( 'Table ', v, ' contains ', #totalRows, ' row', IF(#totalRows>1, 's',''));
END$$
DELIMITER ;
Execution
call countRowsEx('sometable');
You can use information_schema for this.
for example to find rows count for table with name stored in variable v use this:
select table_rows from information_schema.tables where table_name = v;
Try this:
call countRows('v');
I am trying to run a procedure that takes a parameter 'table' for the query, and result as the output parameter. However, it shows as undeclared variable: result
I have doubled checked that no spelling mistake but still have no idea how it happened. Would someone please provide some help or guidance
CREATE DEFINER=`root`#`localhost` PROCEDURE `Function`(IN table varchar(10), OUT result varchar (10))
BEGIN
SET #q = CONCAT ('
Select `field` from `',table,'` into result limit 1;');
PREPARE stmt from #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Try:
...
-- SET #q = CONCAT ('Select `field` from `',table,'` into result limit 1;');
SET #`q` := CONCAT('SELECT `der`.`field`
FROM (SELECT `field` FROM `', `table`, '` LIMIT 1) `der`,
(SELECT #`result` := NULL) `init`
INTO #`result`;');
PREPARE `stmt` from #`q`;
EXECUTE `stmt`;
SET `result` := #`result`;
DEALLOCATE PREPARE `stmt`;
...
It is important to indicate the difference between 9.4. User-Defined Variables and routine parameters 13.1.15. CREATE PROCEDURE and CREATE FUNCTION Syntax, are different variables.
SQL Fiddle demo
1)Below is the code I'm trying for a procedure where I need to compare the count from two different tables. (tbl1 and tbl2 are in parameters to be passed).
But in the above code the values for 'a' and 'b' are set as statements. I need the resultant value(count) from the two statements to compare in the 'IF' condition.
declare a integer;
declare b integer;
set #a:=concat('select count(*) from ', tbl1);
/*PREPARE stmt1 FROM #a;
execute stmt1;
deallocate PREPARE stmt1;*/
set #b:= concat('select count(*) from ', tbl2);
/*PREPARE stmt2 FROM #b;
execute stmt2;
deallocate PREPARE stmt2;*/
if
#a=#b
then
select 1;
else
select 2;
end if;
2) Actually where I am facing a problem to set 'tbl1' and 'tbl2' as parameters in procedure.
The below code works fine if the table names are given directly, but i need them as parameters.
CREATE PROCEDURE myproc (in tbl1 varchar(50), in tbl2 varchar(50))
declare a integer;
declare b integer;
set #a:=(select count(*) from tbl1);
/*PREPARE stmt1 FROM #a;
execute stmt1;
deallocate PREPARE stmt1;*/
set #b:= (select count(*) from tbl2);
/*PREPARE stmt2 FROM #b;
execute stmt2;
deallocate PREPARE stmt2;*/
if
#a=#b
then
select 1;
else
select 2;
end if;
Hope anyone out there can help me with the solution.
As mentioned in the comments above, it is likely that you shouldn't be doing this at all... but, for what it's worth:
SET #sql := CONCAT('SELECT (
SELECT COUNT(*) FROM `',REPLACE('`','``',tbl1),'`
) = (
SELECT COUNT(*) FROM `',REPLACE('`','``',tbl2),'`
);');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #sql := NULL;
REPLACE() has been used to try and avoid SQL injection (it's somewhat crude, but it's the best one can do without further information).
I have a stored procedure that works, but when I pass a value with a hyphen in it, it errors.
I call my procedure with a value like call create('server-v01',555); and I get the following error:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-v01' at line 1
My procedure is as follows:
DELIMITER $$
CREATE PROCEDURE ct(tname varchar(20), sessionsnum INT(11))
BEGIN
DECLARE maxnum INT;
SET #s = CONCAT('INSERT INTO sessions_poll (server_name,sessions_num) VALUES(''',tname,''',',sessionsnum,')');
PREPARE stm FROM #s;
EXECUTE stm;
SET #s = CONCAT('DROP TABLE IF EXISTS ', tname);
PREPARE stm FROM #s;
EXECUTE stm;
SET #s = CONCAT('CREATE TABLE ', tname, ' (num INT, max INT)');
PREPARE stm FROM #s;
EXECUTE stm;
SELECT #maxnum:=max(sessions_num) INTO maxnum FROM sessions_poll WHERE server_name=tname AND DATE(ts)=CURDATE();
SET #s = CONCAT('INSERT INTO ', tname, ' (num,max) VALUES (', sessionsnum,',',maxnum,')');
PREPARE stm FROM #s;
EXECUTE stm;
END $$
DELIMITER ;
My question is, how can I handle a variable with a hyphen in it?
Your question is not how to handle variable with a dash, but how to handle a table with a dash. Your procedure tries to create a table with a name specified in tname. To create (or drop) a table like this you need to quote it with backticks.
DROP TABLE IF EXISTS `server-01`;
In particular you need to
SET #s = CONCAT('DROP TABLE IF EXISTS `', tname, '`');
and the same for other instances.
Whether this is what you really want to do is a question, though ;-)