I want to loop through an associative array that represents a table's columns and values, and call a stored procedure on each iteration that will insert each value into its respective column. The assoc. array and loop looks like this:
public static function update(
int $auctionId,
string $title,
string $description
) : void
{
$new = [
'auction_title' => $title,
'description' => $description
];
foreach ($new as $columnName => $value) {
Database::conn()->callSP('sp_auctions_update', [$auctionId, $columnName, $value]);
}
}
The stored procedure looks like this:
DELIMITER $$
DROP PROCEDURE IF EXISTS sp_auctions_update $$
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName,
IN value,
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
UPDATE auctions SET #columnName=#value, WHERE id=#auctionId;
END $$
DELIMITER ;
Is this possible to do? Or is there a better alternative? Many thanks
do you know what the prepared statement would look like in this instance?
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert column name from variable into it
SET #sql := CONCAT('UPDATE auctions SET ', columnName, '=? WHERE id=?;');
-- Reassign parameters values from local variables to user-defined ones
-- because local variables cannot be used in USING
SET #value := `value`;
SET #auctionId := auctionId;
-- Prepare and execute the query
PREPARE stmt FROM #sql;
EXECUTE stmt USING #value, #auctionId;
DEALLOCATE PREPARE stmt;
END
Alternatively you may concat ALL parameters values into the query text:
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert parameters from variables into it
SET #sql := CONCAT('UPDATE auctions SET ', columnName, '=\'', `value`, '\' WHERE id=', auctionId, ';');
-- Prepare and execute the query
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Caution.
The columnName parameter value is inserted into SQL query text as-is - so injection is possible. You must add the code which controls this parameter value. For example you may check that the column with provided name exists in table structure.
Another 2 parameters cannot be a source of injection due to their numeric datatype.
I am giving two parameters as tlb_name for table name and id as id for deleting the row. Somehow it is not showing any error but after the execution of stored procedure, that particular row was not deleted from table.
`begin
if tlb_name='patients'
then
select 'YES';
set #t1=CONCAT("delete from" ,tlb_name, " where id= ? ");
set #id := id;
PREPARE stmt3 from #t1;
EXECUTE stmt3 USING #id;
DEALLOCATE PREPARE stmt3;
else
select 'Invalid User !!!!' ;
end if;
end`
M trying to create pagination with stored procedure,
when I try to pass 1 as param it get record 0 to 14.
and when I pass 2 as param it gives 0-30,
I want 15-30 when I pass 2 as param
create PROCEDURE abc(pageno INT)
BEGIN
DECLARE page_no int;
DECLARE rstarts int;
DECLARE rends int;
DECLARE userPage int;
set #userPage = pageno;
PREPARE STMT FROM
" SELECT * FROM primaryinfo LIMIT ?,? ";
SET #START =(#userPage - 1) * 15;
SET #LIMIT = #userPage * 15;
EXECUTE STMT USING #START, #LIMIT;
DEALLOCATE PREPARE STMT;
END
or is there any other solution to do it effectively..
Thank you in advance
pagination without statements:
create PROCEDURE test(
IN first_rec integer,
IN rec_count integer
)
BEGIN
-- return --
SET #rownum=0;
SELECT * FROM (
SELECT
user.*, #rownum:=#rownum+1 AS rn FROM user
) t WHERE rn>=first_rec and rn<first_rec+rec_count;
END;;
I have a table in which i want to insert multiple rows having values from a php array , now i can't figure out how to pass an array in stored procedure .
Example-: i have a php array having names ['sqlite','mysql','sql']
now what i want is to send this array to stored procedure and loop through the array taking one value at a time and inserting into the database table.
You can pass a string with your list and use a prepared statements to run a query, e.g. -
DELIMITER $$
CREATE PROCEDURE GetFruits(IN fruitArray VARCHAR(255))
BEGIN
SET #sql = CONCAT('SELECT * FROM Fruits WHERE Name IN (', fruitArray, ')');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
DELIMITER ;
How to use:
SET #fruitArray = '\'apple\',\'banana\'';
CALL GetFruits(#fruitArray);
SELECT *
FROM fruits
WHERE FIND_IN_SET ( name, fruit_array );
Hope this will help you..
Another Solution:
Use foreach loop:
foreach(condition)
{
//Create insert query string
}
//insert query
//Execute Query
For more help paste code
I have created procedure as below. I am passing table name and limit along with username,
DELIMITER $$
DROP PROCEDURE IF EXISTS `GetPosteingang`$$
CREATE PROCEDURE `GetPosteingang`
(
IN stlimit INT,
IN tblname VARCHAR(100),
IN userId INT
)
BEGIN
DECLARE t1 VARCHAR(5000);
SET #t1 =
"SELECT msg_id,msg_from_name as fromname,msg_titel as title,msg_date as date,msg_gelesen,msg_replied,msg_nodel,'msg' as type
FROM "+#tblname+"
UNION
SELECT files_id as msg_id,from_username as fromname,files_oname as title,files_time as date,files_name as msg_gelesen,files_extension as msg_replied,files_filesize as msg_nodel,'file' as type
FROM community_files
WHERE user_id = "+#userId+"
ORDER BY date DESC
LIMIT "+#stlimit+",30";
#SET #t1 =CONCAT('SELECT * FROM ',tab_name );
PREPARE STMT FROM #t1;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
END $$
DELIMITER ;
But when I call this,
CALL GetPosteingang('1','community_msgin8','658468');
It is giving me error,
CALL GetPosteingang('1','community_msgin8','658468') Error Code: 1064. 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 'NULL' at line 1
Please help me out.
+ is not a string concatenation operator—use MySQL's CONCAT() function instead;
user-defined (session) variables (which are prefixed with #) are different to stored-program/declared variables (which have no prefix);
beware of your procedure being called with a tblname that results in SQL injection;
column names in a UNION are determined by the first query; and
parameterise your prepared statement, where possible.
Therefore:
CREATE PROCEDURE `GetPosteingang`
(
IN stlimit INT,
IN tblname VARCHAR(100),
IN userId INT
)
BEGIN
SET #t1 := CONCAT("
SELECT msg_id,
msg_from_name AS fromname,
msg_titel AS title,
msg_date AS date,
msg_gelesen,
msg_replied,
msg_nodel,
'msg' AS type
FROM `", REPLACE('`','``',tblname), "`
UNION
SELECT files_id,
from_username,
files_oname,
files_time,
files_name,
files_extension,
files_filesize,
'file' as type
FROM community_files
WHERE user_id = ?
ORDER BY date DESC
LIMIT ?, 30
", #t2 := userId, #t3 := stlimit;
PREPARE stmt FROM #t1;
EXECUTE stmt USING #t2, #t3;
DEALLOCATE PREPARE stmt;
END$$
However, all that said, having a variable table name is a strong indicator that your schema is badly denormalised—consider merging all such tables together into a single one with columns that identify their differences.
The code above is missing the end parenthesis for the CONCAT function. So it should be this:
CREATE PROCEDURE `GetPosteingang`
(
IN stlimit INT,
IN tblname VARCHAR(100),
IN userId INT
)
BEGIN
SET #t1 := CONCAT("
SELECT msg_id,
msg_from_name AS fromname,
msg_titel AS title,
msg_date AS date,
msg_gelesen,
msg_replied,
msg_nodel,
'msg' AS type
FROM `", REPLACE('`','``',tblname), "`
UNION
SELECT files_id,
from_username,
files_oname,
files_time,
files_name,
files_extension,
files_filesize,
'file' as type
FROM community_files
WHERE user_id = ?
ORDER BY date DESC
LIMIT ?, 30
"), #t2 := userId, #t3 := stlimit;
PREPARE stmt FROM #t1;
EXECUTE stmt USING #t2, #t3;
DEALLOCATE PREPARE stmt;
END$$