Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Instrução Preparada de Procedimento Armazenado do MySQL (SQL Dinâmico) Parametrizada


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;