MySQL WHERE
Filtering rows is the most common reason to bind parameters. Never interpolate user input — that's how SQL injection happens.
Single filter
PHP
$stmt = $pdo->prepare('SELECT * FROM customers WHERE country = ?');
$stmt->execute(['AU']);
foreach ($stmt as $row) {
echo $row['name'], PHP_EOL;
}
Multiple filters
PHP
$stmt = $pdo->prepare(
'SELECT id, name FROM customers WHERE active = ? AND country = ?'
);
$stmt->execute([1, 'AU']);
Named placeholders
PHP
$stmt = $pdo->prepare(
'SELECT id, name FROM customers WHERE country = :country AND active = :active'
);
$stmt->execute([
':country' => 'AU',
':active' => 1,
]);
Named are easier to read; positional are less typing. Pick a style and stay consistent.
LIKE patterns
PHP
$stmt = $pdo->prepare("SELECT * FROM customers WHERE email LIKE ?");
$stmt->execute(['%@example.com']); // wildcards in the BIND, not the SQL
IN (...) — dynamic list
Placeholders don't expand a list — generate one per value:
PHP
$countries = ['AU', 'NZ', 'US'];
$marks = implode(',', array_fill(0, count($countries), '?'));
$stmt = $pdo->prepare("SELECT * FROM customers WHERE country IN ($marks)");
$stmt->execute($countries);
Range conditions
PHP
$stmt = $pdo->prepare(
'SELECT * FROM orders WHERE created_at >= ? AND created_at < ?'
);
$stmt->execute(['2026-01-01', '2026-02-01']);
Tip: Never put column or table names in placeholders — only values bind. If a column name is user-input (e.g. dynamic sort), allow-list it:
$col = in_array($_GET['sort'], ['name','age']) ? $_GET['sort'] : 'id';.Example
Example
<?php
$stmt = $pdo->prepare('SELECT * FROM customers WHERE country = ?');
$stmt->execute(['AU']);
print_r($stmt->fetchAll());
Try it Yourself »
Exercise
Positional placeholder character.
WHERE country =
One character.
Discussion
Loading…