Podobnie jak w przypadku prawie wszystkich pytań „Jak zrobić SQL z poziomu PHP” — naprawdę powinien korzystać z przygotowanych oświadczeń. To nie takie trudne:
$ids = array(2, 4, 6, 8);
// prepare an SQL statement with a single parameter placeholder
$sql = "UPDATE MyTable SET LastUpdated = GETDATE() WHERE id = ?";
$stmt = $mysqli->prepare($sql);
// bind a different value to the placeholder with each execution
for ($i = 0; $i < count($ids); $i++)
{
$stmt->bind_param("i", $ids[$i]);
$stmt->execute();
echo "Updated record ID: $id\n";
}
// done
$stmt->close();
Alternatywnie możesz to zrobić w ten sposób:
$ids = array(2, 4, 6, 8);
// prepare an SQL statement with multiple parameter placeholders
$params = implode(",", array_fill(0, count($ids), "?"));
$sql = "UPDATE MyTable SET LastUpdated = GETDATE() WHERE id IN ($params)";
$stmt = $mysqli->prepare($sql);
// dynamic call of mysqli_stmt::bind_param hard-coded eqivalent
$types = str_repeat("i", count($ids)); // "iiii"
$args = array_merge(array($types), $ids); // ["iiii", 2, 4, 6, 8]
call_user_func_array(array($stmt, 'bind_param'), ref($args)); // $stmt->bind_param("iiii", 2, 4, 6, 8)
// execute the query for all input values in one step
$stmt->execute();
// done
$stmt->close();
echo "Updated record IDs: " . implode("," $ids) ."\n";
// ----------------------------------------------------------------------------------
// helper function to turn an array of values into an array of value references
// necessary because mysqli_stmt::bind_param needs value refereces for no good reason
function ref($arr) {
$refs = array();
foreach ($arr as $key => $val) $refs[$key] = &$arr[$key];
return $refs;
}
Dodaj więcej symboli zastępczych parametrów dla innych pól, jeśli ich potrzebujesz.
Który wybrać?
-
Pierwszy wariant działa iteracyjnie ze zmienną liczbą rekordów, wielokrotnie trafiając do bazy danych. Jest to najbardziej przydatne przy operacjach UPDATE i INSERT.
-
Drugi wariant również działa ze zmienną liczbą rekordów, ale trafia do bazy danych tylko raz. Jest to znacznie bardziej wydajne niż podejście iteracyjne, oczywiście możesz zrobić to samo tylko ze wszystkimi rekordami, których to dotyczy. Jest to najbardziej przydatne w przypadku operacji SELECT i DELETE lub gdy chcesz UPDATE wielu rekordów z tymi samymi danymi.
Dlaczego przygotowane wyciągi?
- Przygotowane instrukcje są dużo bezpieczniejsze, ponieważ uniemożliwiają ataki typu SQL injection. Jest to główny powód, dla którego warto korzystać z przygotowanych oświadczeń, nawet jeśli ich napisanie wymaga więcej pracy. Rozsądnym nawykiem jest:Zawsze używaj przygotowanych stwierdzeń, nawet jeśli uważasz, że „nie jest to naprawdę konieczne”. Zaniedbanie przyjdzie i ugryzie Ciebie (lub Twoich klientów).
- Ponowne użycie tej samej przygotowanej instrukcji wielokrotnie z różnymi wartościami parametrów jest bardziej wydajne niż wysyłanie wielu pełnych ciągów SQL do bazy danych, ponieważ baza danych musi skompilować instrukcję tylko raz i może ją również ponownie wykorzystać.
- Tylko wartości parametrów są wysyłane do bazy danych w
execute()
, więc przy wielokrotnym użyciu mniej danych musi przejść przez przewód.
W dłuższych pętlach różnica czasu wykonania między użyciem przygotowanej instrukcji a wysłaniem zwykłego SQL stanie się zauważalna.