问题
I have a simple table with some data:
DROP TABLE IF EXISTS `MY_TABLE`;
CREATE TABLE IF NOT EXISTS `MY_TABLE` (
`id` CHAR(40) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `MY_TABLE` (`id`) VALUES (1);
INSERT INTO `MY_TABLE` (`id`) VALUES (2);
INSERT INTO `MY_TABLE` (`id`) VALUES (3);
Now I have a procedure to retrieve this data ordering from a column. This works as expected:
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER $$
CREATE PROCEDURE test_procedure()
BEGIN
SELECT id AS columnAlias FROM `MY_TABLE`
ORDER BY columnAlias;
END $$
DELIMITER ;
CALL test_procedure(); /* Returns 1, 2, 3, 4, 5, 6, 7, 8, 9 */
As well as this:
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER $$
CREATE PROCEDURE test_procedure()
BEGIN
SELECT id AS columnAlias FROM `MY_TABLE`
ORDER BY -columnAlias;
END $$
DELIMITER ;
CALL test_procedure(); /* Should return 9, 8, 7, 6, 5, 4, 3, 2, 1 */
Now, my case: the column name has to be passed from the procedure, so I do:
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER $$
CREATE PROCEDURE test_procedure(IN data JSON)
BEGIN
SET @sortBy = JSON_UNQUOTE(JSON_EXTRACT(DATA, '$.sortBy'));
SELECT id AS columnAlias FROM `MY_TABLE`
ORDER BY @sortBy;
END $$
DELIMITER ;
CALL test_procedure('{"sortBy": "columnAlias"}'); /* Should return 1, 2, 3, 4, 5, 6, 7, 8, 9 */
CALL test_procedure('{"sortBy": "-columnAlias"}'); /* Should return 9, 8, 7, 6, 5, 4, 3, 2, 1 */
But can't make it work. Any help will be welcome.
EDIT:
Given the solution by @bill_karwin I tried to use a CASE, testing agains my variable:
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER $$
CREATE PROCEDURE test_procedure(IN data JSON)
BEGIN
SET @sortBy = JSON_UNQUOTE(JSON_EXTRACT(DATA, '$.sortBy'));
SELECT id AS columnAlias FROM `MY_TABLE`
ORDER BY
CASE @sortBy
WHEN "columnAlias" THEN columnAlias
WHEN "-columnAlias" THEN -columnAlias
END
;
END $$
DELIMITER ;
CALL test_procedure('{"sortBy": "-columnAlias"}');
Doesnt work though, returns 1, 2, 3
, while it should be reversed as I'm passing the string with a minus prepended: -columnAlias
.
回答1:
You could use a CASE expression:
SELECT id AS columnAlias FROM `MY_TABLE`
ORDER BY CASE @sortBy WHEN 'updated_at' THEN updated_at
WHEN 'user_id' THEN user_id
ELSE id END;
Some people use dynamic SQL, but the CASE expression solution is good because it automatically checks the input against a fixed set of columns, so you don't accidentally cause an SQL injection vulnerability.
来源:https://stackoverflow.com/questions/65633858/mysql-5-7-sort-table-by-column-name-using-a-variable-in-stored-procedure