How to write a mysql function with dynamic table name? - mysql

I'm trying to write a my sql function doing the following things:
1- get the table name used in join as a parameter.
but I get mysql syntax error
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 'table DETERMINISTIC
BEGIN select `r`.`id` AS `id`, (case ' at line 2
This is my query
DELIMITER $$
CREATE FUNCTION getTranslation (tablename varchar(50),entity varchar(20),itemid int,lang char(3))
RETURNS table
DETERMINISTIC
BEGIN
select
`r`.`id` AS `id`,
(case
when isnull(`t`.`descr`) then `r`.`descr_ml`
else `t`.`descr`
end) AS `descr`
from
(tablename `r`
left join `g001_translation` `t` ON ((`t`.`item_id` = `r`.`id`)))
END$$
DELIMITER ;
I the select part works fine with static table name by the way.

First up as mentioned by #eggyal this isn't the best way to go about things. But it can be done by using prepared statements. I.e.
DROP PROCEDURE IF EXISTS `exampleOfPrepareStatement`;
CREATE DEFINER = `user`#`%` PROCEDURE `exampleOfPrepareStatement`(inTableName VARCHAR(100))
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
SET #hr1 = CONCAT('
INSERT INTO `',inTableName,'` (
-- fields (can use parameters same as table name if needed)
)
-- either VALUES () or SELECT here
');
-- Prepare, execute, deallocate
PREPARE hrStmt1 FROM #hr1;
EXECUTE hrStmt1;
DEALLOCATE PREPARE hrStmt1;
END;
You can of course add in field names etc. as needed, or use a SELECT or UPDATE etc. This is not ideal, but will do what you are looking for.
I have had to use this in some places before where the same maintenance is being performed on multiple tables which have different field names ( / table names ) and so instead of writing the same function 20 times, instead I use this type of stored procedure which can then be called to do the indexing etc.
As also mentioned by #eggyal , while this may do as you ask, it might not do as you need. If you can provide more information then you may get a better solution.

Give this a try
SET #ex = CONCAT('select `r`.`id` AS `id`,(case when isnull(`t`.`descr`) then `r`.`descr_ml` else `t`.`descr` end) AS `descr` from (',tablename,' `r` left join `g001_translation` `t` ON ((`t`.`item_id` = `r`.`id`)));');
PREPARE stmt FROM #ex;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You will notice that ',tablename,' will use the parameter passed.

Related

Error Executing This Mysql Sp For Make Refresh Of The Fields Saved In Log Table Through Trigger But I Don't See The Error

This sp generate this Error but when I get the #queryString value and execute it, It's working:
Query 1 ERROR: 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 'CREATE TRIGGER triggers_after_insert AFTER INSERT ON mydb.mytable F' at line 2
This error is generated when I execute:
CALL prcTriggersLogsRefreshFields('mydb','mytable','myidtable');
This is the code:
DROP PROCEDURE "prcTriggersLogsRefreshFields";
CREATE PROCEDURE "prcTriggersLogsRefreshFields"(
par_dbName text,
par_tableName text,
par_keyField text
)
BEGIN
SET #strJsonObj = null;
SET #change_object = par_dbName||'.'||par_tableName;
SELECT GROUP_CONCAT('\'',COLUMN_NAME, '\',', COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = par_dbName AND TABLE_NAME = par_tableName INTO #strJsonObj;
SET #queryString = 'DROP TRIGGER `triggers_after_insert`;
CREATE TRIGGER `triggers_after_insert` AFTER INSERT ON `'||par_dbName||'`.`'||par_tableName||'` FOR EACH ROW BEGIN
SELECT JSON_ARRAYAGG(JSON_OBJECT('||#strJsonObj||')) change_obj FROM `'||par_dbName||'`.`'||par_tableName||'` WHERE '||par_keyField||'=New.'||par_keyField||' INTO #jsonRow;
INSERT INTO mylog_db.table_log (`change_id`, `change_date`, `db_name`, `table_name`, `change_object`, `change_event_name`, `previous_content`, `change_content`, `change_user`) VALUES (DEFAULT, NOW(), '''||par_dbName||''', '''||par_tableName||''', '''||#change_object||''', \'insert\', \'{}\', #jsonRow, New.user_created);
END;';
-- select #queryString;
PREPARE stmt FROM #queryString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html says:
SQL syntax for prepared statements does not support multi-statements (that is, multiple statements within a single string separated by ; characters).
You have to run the statements one at a time if you use PREPARE.
There's no need to include the DROP TRIGGER in your prepared statement. You can run the DROP TRIGGER without prepare & execute, since there is no dynamic part in it. Then format the CREATE TRIGGER as a single statement and prepare and execute it.

SELECT JSON_ARRAYAGG FROM TABLE name as parameter problem

I want to have a MySQL procedure, that makes SELECT FROM table and return the result in JSON format via JSON_ARRAYAGG, but the table name to be a parameter.
So there is my solution, but it doesn't work when I call it, because the system thinks the parameter is table name. I will be very thankful if someone can help me.
CREATE DEFINER=`ME` PROCEDURE `main_list`(
IN `the_table` CHAR(50)
)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
BEGIN
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id,'name', NAME)) from the_table;
END
The call and error:
CALL `main_list`('martin');
/* SQL Error (1146): Table 'my_server.the_table' doesn't exist */
As Akina and gotgn already said you can't use tablename in that way and in some other ise PREPARE Statetemnts for it
DELIMITER //
CREATE PROCEDURE `main_list`(
IN `the_table` CHAR(50)
)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
BEGIN
SET #sql := CONCAT("SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id,'name', NAME)) FROM ",the_table);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END//
DELIMITER ;

Conditionally showing part of a query in MySQL stored procedure

I have a MySQL query that I build in php but want to move into a stored procedure. The entire query is good to move into the sproc, except for one complication: In php, depending on a condition, I add a "HAVING ......" as the last line. Is it possible to do a condition, case, etc. to build a query in a similar way?
For example:
PROCEDURE `GeyMyItems`(
IN query VARCHAR(100)
)
BEGIN
SELECT * FROM my_table a
JOIN another_table b ON a.id = b.id
WHERE my_column = 'this_value'
IF (query = 'abc')
HAVING a.my_value = '123';
END$$
DELIMITER ;
I know the syntax of the IF is probably wrong, but I'm just showing what I'm trying to do. Is there a better way to do this?
The only fall back I can think of is to maybe take care of the HAVING portion in php. Just don't include it at all in the SQL, and when I am building my object/array, I can just filter there in my while loop. But I'd like to see how I can utilize a stored procedure for something like this, if at all?
If you're using MySQL 5.0 and later, it's pretty easy.
DELIMITER $$
CREATE PROCEDURE `GetMyItems`(
IN query VARCHAR(100)
)
BEGIN
-- Here you construct your SQL
SET #s = 'SELECT 1';
IF query = 'abc' THEN
SET #s = CONCAT( #s, ',2');
END IF;
-- Here you execute it.
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
This was a similar question here.
to your where clause add this:
and
(
(query = 'abc' and a.my_value ='123')
or query <> 'abc'
)

sql run querys since procedures [duplicate]

This question already has answers here:
Mysql stored procedure don't take table name as parameter
(4 answers)
Closed 6 years ago.
I tried do query since one procedure in mysql
I followed the following:
DELIMITER #
CREATE PROCEDURE returndata(IN xtable CHAR(255), IN xcolumn CHAR(255))
BEGIN
IF (xcolumn = 'XALL') THEN
SELECT * FROM xtable;
ELSE
SELECT xcolumn FROM xtable;
END IF;
END;
#
DELIMITER ;
but gives error. any help is acceptable, or I might say if this is possible?
EDIT error to call the procedure:
MariaDB [pruebab]> CALL returndata('test', 'id');
ERROR 1146 (42S02): Table 'pruebab.xtable' doesn't exist
You cannot pass a table name as a parameter like that. You need to concatenate the variables into an SQL string to use them. See this answer.
Mysql stored procedure don't take table name as parameter
Variables are only evaluated in expressions in queries, not where column or table names are required. You need to use a prepared query.
CREATE PROCEDURE returndata(IN xtable CHAR(255), IN xcolumn CHAR(255))
BEGIN
IF (xcolumn = 'XALL') THEN
SET #SQL = CONCAT('SELECT * FROM ', xtable);
ELSE
SET #SQL = CONCAT('SELECT ', xcolumn, ' FROM ', xtable);
END IF;
PREPARE stmt FROM #SQL;
EXECUTE stmt;
END;

mysql how to pass null parameter into stored procedure and test for it in sql statement

NOTE: Solution for this issue has been attached at the bottom. :)
5.6.17 - MySQL Community Server (GPL) Using MySQL Console
Trying to Test this procedure out in mysql console. It actually involves numerous fields which maybe searched against. Some values maybe defined as NULL.
I was having troubles with the query with an ERROR #1064 which involved a NULL value at line 1.
Here is the query and it breaks when I added the #P1 IS NULL test. I saw this somewhere but cannot for the life of my find it again...
SET #p0='46,51,52,1317,1318,1319,1320,1322,1323';
SET #p1='500-000';
CALL `searchCount2`(#p0, #p1);
DROP PROCEDURE IF EXISTS `searchCount2`//
CREATE PROCEDURE `searchCount2`(
IN _dealerIds varchar(100),
IN _dealerPhoneNumber varchar(10)
)
BEGIN
SET #query = CONCAT('SELECT count(cID)
FROM tblclassifieds c
JOIN tblphotos p
ON c.cmd5val=p.cClassCode
WHERE p.cpMain=1
AND c.cMarkedInappropriate=0
AND c.cBlacklisted=0
AND c.cEndDate>NOW()
AND (cType=29) OR (c.cType=27 OR c.cType=28)
AND c.cCompanyId IN (',_dealerIds,')
AND (("',_dealerPhoneNumber,'" is null) or (c.cPhoneNum="',_dealerPhoneNumber,'"));');
-- SELECT #query;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
Retested the Above using quotes.
Here is the example I have which works before I added the #P1 IS NULL, but as I mentioned this query is far from complete. There are numerous parameters to search against.
DROP PROCEDURE IF EXISTS `searchCount3`//
CREATE PROCEDURE `searchCount3`(
IN _dealerIds varchar(100),
IN _dealerPhoneNumber varchar(10)
)
BEGIN
SET #query = CONCAT('SELECT count(cID)
FROM tblclassifieds c
JOIN tblphotos p
ON c.cmd5val=p.cClassCode
WHERE p.cpMain=1
AND c.cMarkedInappropriate=0
AND c.cBlacklisted=0
AND c.cEndDate>NOW()
AND ((cType=29) OR (cType=27 OR cType=28))
AND c.cCompanyId IN (',_dealerIds,')
OR c.cPhoneNum=',_dealerPhoneNumber,';');
-- SELECT #query;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
SO what is my error with this NULL error? Is there another way I should implement this? How can I test it in MySQL?
Is Set #p1=NULL; valid?
Please disregard the horrible naming convention.
Thanks for any help. I have been struggling with this for too long.
Here is a print off of the query before it executes, SELECT #query:
SELECT count(cID)
FROM tblclassifieds c
JOIN tblphotos p
ON c.cmd5val=p.cClassCode
WHERE p.cpMain=1
AND c.cMarkedInappropriate=0
AND c.cBlacklisted=0
AND c.cEndDate>NOW()
AND (cType=29)
AND c.cCompanyId IN (46,51,52,1317,1318,1319,1320,1322,1323)
OR (cType=27 OR cType=28)
AND cCompanyId IN (46,51,52,1317,1318,1319,1320,1322,1323)
AND ((579-7775 is null) or (c.cPhoneNum=579-7775));
I copy and paste this query into sql console and I get results. But Execute fails! Why is this so? Error #1064.
SOLUTION:
I removed the parameter test for _dealerPhoneNumber IS NULL and replaced it with _dealerPhoneNumber = "". This has fixed the issue.
DROP PROCEDURE IF EXISTS `searchCount2`//
CREATE PROCEDURE `searchCount2`(
IN _dealerIds varchar(100),
IN _dealerPhoneNumber varchar(10)
)
BEGIN
SET #query = CONCAT('SELECT count(cID)
FROM tblclassifieds c
JOIN tblphotos p
ON c.cmd5val=p.cClassCode
WHERE p.cpMain=1
AND c.cMarkedInappropriate=0
AND c.cBlacklisted=0
AND c.cEndDate>NOW()
AND ((cType=29) AND cCompanyId IN (',_dealerIds,'))
OR ((cType=27 OR cType=28) AND cCompanyId IN (',_dealerIds,'))
AND (("',_dealerPhoneNumber,'" = "") or (c.cPhoneNum="',_dealerPhoneNumber,'"));');
-- SELECT #query;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
try to define the parameters as null on the creation.
CREATE PROCEDURE `searchCount3`(
IN _dealerIds varchar(100) = NULL,
IN _dealerPhoneNumber varchar(10) = NULL
)
I had a similar issue. I was passing NULL to a MySQL stored procedure and getting this error message that I thought was obscure:
ERROR #1064 which involved a 'NULL' value at line 1.
I thought maybe passing NULL to stored procedures was not allowed, but it is allowed.
My issue was in the stored procedure, specifically:
I was dynamically generating an insert statement via a call to CONCAT, AND
i was not guarding against the presence of NULL, so i ended up with a quoted 'NULL' in my insert statement
By adding a condition in my string concatenation to account for NULL i was able to fix my issue
BEFORE
...
"more_info_link = '", more_info_link, "', ",
...
AFTER
IF(more_info_link IS NULL,
"more_info_link = NULL, ",
CONCAT("more_info_link = '", more_info_link, "', ")
),