EXECUTE
операторът трябва да получи фиксиран списък от аргументи, така че ще трябва да подготвите и изпълнете израза в IF/THEN/ELSE
блокирай.
IF articlesModule = 1 THEN
SET @query = ... UNION ...
PREPARE stmt FROM @query;
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
ELSE
SET @query = ...; /* no UNION */
PREPARE stmt FROM @query;
EXECUTE stmt USING @searchWordIn, @searchWordIn;
END IF;
Не знам никакъв начин да разреша това в ограничения обхват на езика на съхранената процедура MySQL. За мен това е още една добра причина да не използвам динамичен SQL в запомнените процедури.
За вашите коментари:
Разбирам... можете да използвате CASEкод> изявление
вместо IF/THEN/ELSE
, но всъщност имате 2 =128 потенциални различни случая за низове на заявки, защото предполагам, че всеки от тези 7 модула може да бъде търсен или не.
Алтернатива, която би ви позволила да използвате параметри на заявката, е да забравите за използването на UNION
и вместо това напишете процедурата по такъв начин, че да изпълнява до 7 отделни SELECT
заявки и ги връща като множество набори от резултати . Това е нещо, което запомнените процедури са предназначени да правят. Но трябва да напишете код във вашия PHP слой, за да извлечете всеки набор от резултати на свой ред. Тоест, преминете през наборите от резултати и в този цикъл преминете през редовете на текущия набор от резултати. Вижте пример на PDO::nextRowset()
или mysqli::next_result()
.
Не, не сте в безопасност, ако направите това! Използване на параметър на заявка в PHP за предаване на низ към CALL WEBSITE_mainSearch(?)
е безполезен за защита срещу SQL инжектиране, ако след това свържете тази стойност на параметъра в друг низ вътре в процедурата и извършите динамичен SQL разбор и изпълнение. Използването на параметри на заявката не прави стойностите на параметрите „безопасни“, те просто отделят тези стойности от фазата на SQL анализ.
Вие сте по-безопасни, ако използвате вградената функция на MySQL QUOTE()
при конкатениране на низовете. QUOTE()
прави екраниране на специални знаци, точно като mysql_real_escape_string()
. Освен че е малко по-различен, защото също така произвежда единични кавички, ограничаващи низа, като PDO::quote()
прави.
SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName,
blockID AS itemID, MATCH(blockName, blockBody) AGAINST (',
QUOTE(searchWordIn), ') AS relevance, \'block\' AS itemType
FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (',
QUOTE(searchWordIn),')') ;
Актуализация:още една алтернатива:използвайте UNION
за добавяне на още подзаявки и поддържане на броя на модулите. След това използвайте CASE
за изпълнение на подготвената заявка с различен брой параметри въз основа на натрупания брой.
SET @n = 0;
IF articlesModule = 1 THEN
SET @query = ... UNION ...
SET @n = @n+1;
END IF;
IF newsModule = 1 THEN
SET @query = ... UNION ...
SET @n = @n+1;
END IF;
... and similar for the other 5 modules ...
PREPARE stmt FROM @query;
CASE @n
WHEN 1:
EXECUTE stmt USING @searchWordIn, @searchWordIn;
WHEN 2:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 3:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn;
WHEN 4:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 5:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn;
WHEN 6:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 7:
EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
@searchWordIn, @searchWordIn;
END;