Оператор WHERE: выборка данных из MySQL средствами PHP
Основные принципы работы с WHERE в PHP
Как безопасно и эффективно выполнять запросы с условием WHERE?
Наиболее эффективным речением является использование подготовленных запросов (prepared statements) через PDO или MySQLi. Этот подход предотвращает SQL-инъекции и оптимизирует производительность за счет кеширования плана запроса.
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$id = 5;
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
$user = $stmt->fetch();
?>Php mysql where (оператор where в php и mysql)
Типичная ошибка:
Конкатенация переменной напрямую в SQL-строку. Например: "SELECT * FROM users WHERE id = $id" - это уязвимо для инъекций. Решение - всегда использовать подготовленные запросы.
Как сделать выборку по нескольким условиям с AND/OR?
Условия комбинируются в одном запросе. Параметры передаются в виде массива.
<?php
$minAge = 18;
$city = 'Москва';
$stmt = $pdo->prepare('SELECT * FROM users WHERE age >= :minAge AND city = :city');
$stmt->execute(['minAge' => $minAge, 'city' => $city]);
$users = $stmt->fetchAll();
?>
Проблема:
При большом количестве условий массив параметров может быть громоздким. Используйте именованные плейсхолдеры для ясности.
Как реализовать поиск по части строки (LIKE)?
LIKE используется для поиска шаблонов. Важно экранировать символы % и _ в пользовательском вводе.
<?php
$search = '%'. $term .'%';
$stmt = $pdo->prepare('SELECT * FROM articles WHERE title LIKE :term');
$stmt->execute(['term' => $search]);
?>
Уязвимость:
Если пользователь введёт знак процента, запрос может вернуть неожиданные данные. Решение: экранировать % и _ через str_replace или использовать FULLTEXT поиск для больших текстов.
Как сделать проверку на NULL?
Вместо сравнения с NULL используется оператор IS NULL или IS NOT NULL. В подготовленных запросах значение NULL передаётся через null в PHP.
<?php
$stmt = $pdo->prepare('SELECT * FROM orders WHERE shipped_date IS NULL');
$stmt->execute();
$pendingOrders = $stmt->fetchAll();
?>
Ошибка:
Попытка сравнения с NULL через знак равенства = NULL всегда возвращает FALSE. Используйте IS NULL.
Как использовать IN (список значений)?
IN передаётся через массив, который затем динамически формирует плейсхолдеры.
<?php
$statuses = ['active', 'pending'];
$placeholders = implode(',', array_fill(0, count($statuses), '?'));
$stmt = $pdo->prepare("SELECT * FROM users WHERE status IN ($placeholders)");
$stmt->execute($statuses);
?>
Риск:
Если массив пустой, запрос сломается. Проверяйте count($statuses) > 0.
Как реализовать динамическое построение WHERE в зависимости от входных данных?
Часто требуется фильтр, где некоторые условия опциональны. Нужно собирать массив условий и параметров программно.
<?php
$conditions = [];
$params = [];
if (!empty($_GET['name'])) {
$conditions[] = 'name LIKE :name';
$params['name'] = '%'. $_GET['name'] .'%';
}
if (!empty($_GET['age'])) {
$conditions[] = 'age = :age';
$params['age'] = (int)$_GET['age'];
}
$sql = 'SELECT * FROM users';
if ($conditions) {
$sql .= ' WHERE ' . implode(' AND ', $conditions);
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
?>
Сложность:
Неправильное экранирование или порядок параметров может привести к синтаксической ошибке. Всегда используйте именованные плейсхолдеры с уникальными ключами.
Расширенные примеры использования WHERE
Пример 1: Выборка по диапазону дат с BETWEEN
<?php
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8', 'user', 'pass');
$start = '2024-01-01';
$end = '2024-12-31';
$stmt = $pdo->prepare('SELECT * FROM orders WHERE order_date BETWEEN :start AND :end');
$stmt->execute(['start' => $start, 'end' => $end]);
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($orders);
?>
Array
(
[0] => Array
(
[id] => 101
[order_date] => 2024-03-15
[total] => 1500.00
)
[1] => Array
(
[id] => 102
[order_date] => 2024-06-20
[total] => 2300.00
)
)
Пример 2: Использование подзапроса в WHERE
<?php
$categoryName = 'Электроника';
$stmt = $pdo->prepare('
SELECT p.*
FROM products p
WHERE p.category_id = (
SELECT id FROM categories WHERE name = :cat
)
');
$stmt->execute(['cat' => $categoryName]);
$products = $stmt->fetchAll();
?>
Нет вывода, но в переменной $products будут товары из заданной категории.
Пример 3: Условная выборка с NOT IN и проверкой на NULL
<?php
$excludeIds = [2, 5];
$placeholders = implode(',', array_fill(0, count($excludeIds), '?'));
$stmt = $pdo->prepare("SELECT * FROM users WHERE id NOT IN ($placeholders) AND deleted_at IS NULL");
$stmt->execute($excludeIds);
$activeUsers = $stmt->fetchAll();
?>
Array
(
[0] => Array ( [id] => 1 [name] => Иван ... )
[1] => Array ( [id] => 3 [name] => Мария ... )
)
Пример 4: Комбинация LIKE и REGEXP
<?php
$pattern = '^[0-9]+';
$stmt = $pdo->prepare('SELECT * FROM products WHERE sku REGEXP :pattern');
$stmt->execute(['pattern' => $pattern]);
$numericSku = $stmt->fetchAll();
?>
Выборка товаров, чей артикул начинается с цифр. REGEXP не поддерживает подготовленные плейсхолдеры для самого шаблона в PDO (зависит от версии), поэтому параметр передаётся как строка. На практике лучше экранировать отдельно.
Пример 5: Множественные условия с логическими операторами и приоритетом
<?php
$stmt = $pdo->prepare('
SELECT *
FROM tasks
WHERE (status = :done OR status = :cancelled)
AND assignee_id = :user
');
$stmt->execute([
'done' => 'done',
'cancelled' => 'cancelled',
'user' => 42
]);
?>
Вернёт задачи со статусом 'done' или 'cancelled' для пользователя 42.