MySQL prepared statements with order by clause - mysql

I am using prepared statements in MySQL with 'order by' conditional clause. Using '?' and variables don't work with such things like ordering so I've decided to make it in other way. I set if conditions, but it's much more code. Maybe there is other option to reduce code and just changing 'order by' arguments?
IF sorting_column_index = 1 and sorting_column_mode = 0
THEN PREPARE STMT FROM 'SELECT a.oid as \'oid\',
...
FROM table as a
...
order by numero_annee desc LIMIT ?, ?';
EXECUTE STMT USING #skip, #ROWS;
END IF;
IF sorting_column_index = 2 and sorting_column_mode = 1
THEN PREPARE STMT FROM 'SELECT a.oid as \'oid\',
...
FROM table as a
...
order by numero_ordre asc LIMIT ?, ?';
EXECUTE STMT USING #skip, #ROWS;
END IF;
...

Try something like this, not using parameters for asc/desc but building your query string:
SET #sort_order = 'desc';
SET #my_limit = 5;
SET #sql = CONCAT('SELECT whatever FROM whatever ORDER BY col1 ', #sort_order, ' LIMIT ?;');
PREPARE stmt FROM #sql;
EXECUTE stmt USING #my_limit;
DEALLOCATE PREPARE stmt;

Related

Incorrect parameter count in the call to native function 'JSON_OBJECT'

I'm getting all columns from a table and fetching the result to JSON using the function JSON_OBJECT. But when i execute the stored procedure i'm getting this error.
CREATE DEFINER=`sistema`#`%` PROCEDURE `get_products_as_json`()
BEGIN
SET #fields = (
'SELECT
group_concat(\'\`\', column_name, \'\`\, \', column_name)
FROM
information_schema.columns
WHERE
table_schema = DATABASE()
AND table_name = \'products\'
ORDER BY table_name , ordinal_position'
);
SET #stmt = ('SELECT JSON_OBJECT(?) FROM products LIMIT 10');
PREPARE stmt FROM #stmt;
EXECUTE stmt USING #fields;
DEALLOCATE PREPARE stmt;
END
You cannot use prepared statements in that way.
You have to CONCAT the variable.
I also changed the first SELECT, this works too and is better to read.
DELIMITER $$
CREATE DEFINER=`sistema`#`%` PROCEDURE `get_products_as_json`()
BEGIN
SET #fields = (
SELECT
group_concat('"', column_name, '", ', column_name)
FROM
information_schema.columns
WHERE
table_schema = DATABASE()
AND table_name = 'products'
ORDER BY table_name , ordinal_position
);
SET #stmt = CONCAT('SELECT json_object(',#fields,') FROM products LIMIT 10');
PREPARE stmt FROM #stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
I added also the DELIMITER in case you don_'t use mysql workbench

select list of columns dynamically in MySQL

I've looked through a lot of posts on this site and others and I can't figure this out. I'm trying to select a list of columns from a table and then use them in a query similar to this:
set #cols = (select group_concat(column_name) as 'col_list' FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE (`TABLE_SCHEMA` = 'REPORTS' AND `TABLE_NAME` = 't_labor' AND column_name like '%host%'));
set #s = 'select ' + #cols + ' from REPORTS.t_labor';
prepare stmt from #s;
execute stmt;
deallocate prepare stmt;
-- execute ('select ' + #cols + ' from REPORTS.t_sales');
I am trying to run the above statements as-is. I also tried creating a stored procedure, but I have never worked with stored procedures in MySQL before and I don't know how to debug them. I would prefer to do this without using a stored procedure if possible, but if it's necessary that's ok.
I tried using the prepare statement, and I tried the execute statement but I couldn't get either to work.
Wild guess here, but try this.
set #cols = (select group_concat(column_name) as 'col_list' FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE (`TABLE_SCHEMA` = 'REPORTS' AND `TABLE_NAME` = 't_labor' AND column_name like '%host%'));
PREPARE stmt1 FROM 'select ? from REPORTS.t_labor';
EXECUTE stmt1 USING #cols;
DEALLOCATE PREPARE stmt1;
Finally figured it out:
set #cols = (select group_concat(column_name) as 'col_list' FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE (`TABLE_SCHEMA` = 'REPORTS' AND `TABLE_NAME` = 't_labor' AND column_name like '%host%'));
set #qry = concat('select ', #cols, ' from REPORTS.t_labor');
PREPARE stmt1 FROM #qry;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
Had to piece together replies from at least 5 different posts similar to this question plus Dr OSWaldo's reply.

Alternative for Find_in_set which can use index

I have a my sql stored procedure where i am passing a list of numbers as a comma separated mediumtext field
For checking if my parameter matched i am using Find_in_set in my stored procedure as follows
SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4 FROM `mytable`
WHERE FIND_IN_SET(f2,'1,2,4,5,6,6,7,8,8,4,9,7.......................') > 0
ORDER BY f1 DESC
LIMIT 25 OFFSET 0
;
SELECT FOUND_ROWS();
Now problems with Find_in_set i found out later is that it doesn't used index due to which My query is taking too long to complete.
Please suggest any improvement in the query
P.S.
Following is my complete stored procedure (including the changes as suggested in below answer)
DECLARE _calculated_offset INT;
SET _calculated_offset = _limit * (_pageNumber -1);
IF _calculated_offset < 0 THEN
SET _calculated_offset = 0;
END IF;
/*SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4 FROM `mytable`
WHERE FIND_IN_SET(f1,_telcoIdList) > 0
AND FIND_IN_SET(f2,_msisdnList) > 0
ORDER BY f3 DESC
LIMIT _limit OFFSET _calculated_offset
;
SELECT FOUND_ROWS();*/
SET #query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4
FROM `mytable`
WHERE f1 in (',_telcoIdList,')
AND f2 in (',_msisdnList,')
ORDER BY f3 DESC
LIMIT ', _limit,' OFFSET ',_calculated_offset,' ;
SELECT FOUND_ROWS();
');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Use prepared statement and change to in clause
SET #query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4 FROM mytable
WHERE f2 in (', myinputstr, ') ORDER BY f1 DESC LIMIT 25 OFFSET 0');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
This will allow the f2 index to be used.
EDIT : To include foundrows statement, use the following style
SET #query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4
FROM `mytable`
WHERE f1 in (',_telcoIdList,')
AND f2 in (',_msisdnList,')
ORDER BY f3 DESC
LIMIT ', _limit,' OFFSET ',_calculated_offset);
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT FOUND_ROWS();
BTW, added SQL_CALC_FOUND_ROWS too in the query

Paramater for name of a table without using prepare statement in MySQL

can i somehow set parameter for name of table in query without using a prepare statement?
This is example:
SET #tableName = 'Customer';
SELECT * FROM #tableName;
Thanks
Depending on the version of MySQL you are using, you may be able to use something like:
SET #tableName = 'Customer';
SET #s = CONCAT('SELECT * FROM ', #tableName);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

How to select from MySQL where Table name is Variable

I have a case where getting the table name should be from a set variable like:
SET #ID_1 = (SELECT ID FROM `slider` LIMIT 0,1);
SET #Cat = (SELECT Category FROM `slider` LIMIT 0,1);
select * from #Cat where ID = #ID_1
but doing that way MySQL outputs an error, so could someone show me how I can achieve that, because these are my baby steps in MySQL.
You'd have to do this with a prepared statement. Something like:
SET #s = CONCAT('select * from ', #Cat, ' where ID = ', #ID_1);
PREPARE stmt1 FROM #s;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;