Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Vorbereitete MySQL-Anweisung für gespeicherte Prozeduren (Dynamic SQL) Parametrisiert

Die EXECUTE -Anweisung muss eine feste Liste von Argumenten gegeben werden, also müssen Sie und vorbereiten Führen Sie die Anweisung in einem IF/THEN/ELSE aus blockieren.

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;

Ich kenne keine Möglichkeit, dies im begrenzten Umfang der gespeicherten Prozedursprache von MySQL zu lösen. Für mich ist das ein weiterer guter Grund, dynamisches SQL nicht in gespeicherten Prozeduren zu verwenden.

Zu Ihren Kommentaren:

Ich verstehe ... Sie könnten einen CASE Erklärung anstelle eines IF/THEN/ELSE , aber Sie haben tatsächlich 2 =128 potenzielle unterschiedliche Fälle für Abfragezeichenfolgen, da ich annehme, dass jedes dieser 7 Module entweder durchsucht werden kann oder nicht.

Eine Alternative, die es Ihnen ermöglichen würde, Abfrageparameter zu verwenden, besteht darin, die Verwendung von UNION zu vergessen , und schreiben Sie stattdessen die Prozedur so, dass bis zu 7 separate SELECT ausgeführt werden Abfragen und gibt sie alle als mehrere Ergebnismengen zurück . Das ist etwas, was gespeicherte Prozeduren tun sollen. Aber Sie müssen Code in Ihre PHP-Schicht schreiben, um jede Ergebnismenge der Reihe nach abzurufen. Das heißt, die Ergebnismengen durchlaufen und innerhalb dieser Schleife die Zeilen der aktuellen Ergebnismenge durchlaufen. Siehe Beispiel unter PDO::nextRowset() oder mysqli::next_result() .

Nein, Sie sind nicht sicher, wenn Sie das tun! Verwenden eines Abfrageparameters in PHP, um eine Zeichenfolge an CALL WEBSITE_mainSearch(?) zu übergeben ist zum Schutz vor SQL-Injection nutzlos, wenn Sie diesen Parameterwert dann innerhalb der Prozedur mit einer anderen Zeichenfolge verketten und eine dynamische SQL-Analyse und -Ausführung durchführen. Die Verwendung von Abfrageparametern macht Parameterwerte nicht "sicher", sie trennt diese Werte lediglich von der SQL-Parse-Phase.

Sie sind sicherer, wenn Sie die eingebaute Funktion von MySQL verwenden QUOTE() beim Verketten der Strings. QUOTE() maskiert Sonderzeichen, genau wie mysql_real_escape_string() . Nur dass es etwas anders ist, weil es auch die einfachen Anführungszeichen erzeugt, die die Zeichenfolge begrenzen, wie PDO::quote() tut.

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),')') ;

Update:Eine weitere Alternative:Verwenden Sie UNION um weitere Unterabfragen hinzuzufügen und die Module zu zählen. Verwenden Sie dann einen CASE um die vorbereitete Abfrage basierend auf der kumulierten Anzahl mit einer anderen Anzahl von Parametern auszuführen.

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;