EXECUTE
uttalandet måste ges en fast lista med argument, så du måste förbereda och exekvera satsen i en IF/THEN/ELSE
blockera.
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;
Jag vet inte något sätt att lösa detta i den begränsade omfattningen av MySQL-lagrade procedurspråk. För mig är det ytterligare ett bra skäl att inte använda dynamisk SQL i lagrade procedurer.
Angående dina kommentarer:
Jag förstår... du kan använda ett CASE uttalande
istället för en IF/THEN/ELSE
, men du har faktiskt 2 =128 potentiella olika fall för frågesträngar, eftersom jag antar att någon av dessa 7 moduler antingen kan sökas eller inte.
Ett alternativ som skulle tillåta dig att använda frågeparametrar är att glömma att använda UNION
, och skriv istället proceduren på ett sådant sätt som kör upp till 7 separata SELECT
frågor och returnerar alla som flera resultatuppsättningar . Det är något som lagrade procedurer är avsedda att göra. Men du måste skriva kod i ditt PHP-lager för att hämta varje resultatuppsättning i tur och ordning. Det vill säga, loop över resultatuppsättningarna, och inom den loopen, loop över raderna i den aktuella resultatuppsättningen. Se exempel på PDO::nextRowset()
eller mysqli::next_result()
.
Nej, du är inte säker om du gör det! Använda en frågeparameter i PHP för att skicka en sträng till CALL WEBSITE_mainSearch(?)
är värdelöst för att skydda mot SQL-injektion, om du sedan sammanfogar det parametervärdet till en annan sträng i proceduren och gör en dynamisk SQL-parse-and-execute. Att använda frågeparametrar gör inte parametervärden "säkra", de separerar bara dessa värden från SQL-analysfasen.
Du är säkrare om du använder MySQL:s inbyggda funktion CITAT()
vid sammanlänkning av strängarna. QUOTE()
gör escape av specialtecken, precis som mysql_real_escape_string()
. Förutom att det är något annorlunda, eftersom det också producerar enkla citattecken som avgränsar strängen, som PDO::quote()
gör.
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),')') ;
Uppdatering:ytterligare ett alternativ:använd UNION
för att lägga till fler underfrågor och hålla räkningen av modulerna. Använd sedan en CASE
för att utföra den förberedda frågan med ett annat antal parametrar baserat på det ackumulerade antalet.
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;