O
EXECUTAR
declaração deve receber uma lista fixa de argumentos, então você terá que preparar e execute a instrução em um IF/THEN/ELSE
quadra. 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;
Não conheço nenhuma maneira de resolver isso no escopo limitado da linguagem de procedimento armazenado do MySQL. Para mim, é outro bom motivo para não usar SQL dinâmico em procedimentos armazenados.
Re seus comentários:
Entendo... você poderia usar um
CASE declaração
em vez de um IF/THEN/ELSE
, mas na verdade você tem 2 =128 casos diferentes em potencial para strings de consulta, porque presumo que qualquer um desses 7 módulos possa ser pesquisado ou não. Uma alternativa que permitiria usar parâmetros de consulta é esquecer de usar
UNION
, e, em vez disso, escreva o procedimento de forma que execute até 7 SELECT
separados consulta e retorna todos eles como vários conjuntos de resultados . Isso é algo que os procedimentos armazenados se destinam a fazer. Mas você precisa escrever código em sua camada PHP para buscar cada conjunto de resultados por vez. Ou seja, faça um loop sobre os conjuntos de resultados e, dentro desse loop, faça um loop sobre as linhas do conjunto de resultados atual. Veja o exemplo em PDO::nextRowset()
ou mysqli::next_result()
. Não, você não estará seguro se fizer isso! Usando um parâmetro de consulta em PHP para passar uma string para o
CALL WEBSITE_mainSearch(?)
é inútil para proteção contra injeção de SQL, se você concatenar esse valor de parâmetro em outra string dentro do procedimento e fizer uma análise e execução de SQL dinâmica. O uso de parâmetros de consulta não torna os valores de parâmetro "seguros", eles apenas separam esses valores da fase de análise SQL. Você está mais seguro se usar a função integrada do MySQL CITAÇÃO() ao concatenar as strings.
QUOTE()
faz escape de caracteres especiais, assim como mysql_real_escape_string()
. Exceto que é um pouco diferente, porque também produz as aspas simples que delimitam a string, como PDO::quote()
faz. 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),')') ;
Atualização:mais uma alternativa:use
UNION
para adicionar mais subconsultas e manter a contagem dos módulos. Em seguida, use um CASE
para executar a consulta preparada com um número diferente de parâmetros com base na contagem acumulada. 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;