Оператор WHERE: выборка данных из MySQL средствами PHP

Раздел: Базы данных -> SQL запросы

Основные принципы работы с 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.

Оператор WHERE в PHP и MySQL - comments

En
Php mysql where (php)