PHP LinuxWindowsmacOS

PHP: PDO HY093 Invalid parameter number при повторном использовании параметра

  • Обновлено
  • Чтение ≈ 3 минуты

Краткий ответ

Причины SQLSTATE[HY093] Invalid parameter number, когда один именованный параметр использован дважды в PDO, и безопасная правка без включения эмуляции запросов.

В этой статье
  1. Когда возникает ошибка
  2. Причины и признаки
  3. Пошаговая диагностика и устранение
  4. Проверяемый пример и команды
  5. Проверка исправления и действия при неудаче

#Когда возникает ошибка

PDO может выдать SQLSTATE[HY093]: Invalid parameter number, когда SQL использует одну метку :term дважды, а подстановка выполняется нативно без эмуляции. Руководство PHP требует уникальные имена параметров для каждого вхождения при отключённой эмуляции. Сама ошибка бывает и из-за несовпадения количества меток со списком execute(), поэтому сначала нужно найти конкретный SQL.

#Причины и признаки

Возможная причинаКак узнатьЧто делать
Одна метка повторена дваждыНапример, name = :term OR email = :term с нативной подготовкой.Строка SQL содержит несколько :term, а execute привязывает только один ключ.Назовите метки :term_name и :term_email и передайте обе.
Лишние или недостающие параметрыМассив execute() не совпадает с метками в SQL.В тексте сообщения HY093 нет связи с дублем, но есть неправильное число меток.Пересчитайте имена и ключи, не смешивайте вопросительные и именованные метки.
Различаются драйвер и режим подготовкиРазные окружения могут использовать разный PDO-драйвер или режим ATTR_EMULATE_PREPARES.Запрос проходит в одном окружении, падает в другом.Используйте уникальные метки, независимые от включения эмуляции.

#Пошаговая диагностика и устранение

  1. Снимите SQLSTATE и место создания запросаВ закрытом журнале приложения найдите SQLSTATE[HY093], файл и строку PDOStatement->execute(); не публикуйте SQL с личными данными. Найдите соответствующий вызов $pdo->prepare($sql). На рабочей базе не тестируйте исходный запрос, если он меняет данные: начните с копии и с чтения SELECT.
  2. Сосчитайте все параметры и их именаОткройте SQL в редакторе и найдите :name либо ?, не считая двоеточия в строковых литералах и комментариях. Проверьте повтор :term и массив аргументов execute(). Если используется один стиль ?, количество значений должно соответствовать маркерам. Нельзя передать имя таблицы или SQL-выражение как параметр.
  3. Проверьте режим подготовки без изменения конфигурацииВ отдельной диагностике под тем же пользователем и подключением проверьте драйвер через $pdo->getAttribute(PDO::ATTR_DRIVER_NAME). Для драйверов, поддерживающих атрибут, можно посмотреть ATTR_EMULATE_PREPARES; отсутствие поддержки не означает ошибку. Не включайте эмуляцию повсеместно: она меняет поведение и скрывает проблему повторных имён.
  4. Замените повторяющееся имя на независимые меткиВ тестовой копии измените SQL: WHERE name = :term_name OR email = :term_email. В $stmt->execute([...]) добавьте обе разные метки с тем же значением поиска. Если значение должно отличаться по полям (например, поиск по email и имени), нормализуйте их отдельно перед выполнением.
  5. Защитите границы пользовательского поискаПроверьте, что строка поиска передаётся через параметры, а не склеивается с текстом SQL. Для поиска с LIKE экранирование символов % и _ определяется правилами СУБД, а это отдельная задача; не объявляйте пример с точным равенством универсальным решением для LIKE. Секрет подключения не сохраняйте в диагностических файлах.
  6. Проверьте SELECT и остальные сценарииЗапустите изменённый подготовленный SELECT на тестовой базе с обычным запросом, пустым запросом и строкой с кавычкой. Ошибка HY093 должна исчезнуть, результаты должны соответствовать условиям. Для UPDATE/DELETE выполняйте сначала транзакцию на копии и проверку затронутых строк; не пробуйте исправление сразу на рабочей базе.
  7. Если ошибка осталась — сверяйте фактический SQL и аргументыСравните количество и точное написание всех именованных меток с ключами массива execute(). Изменения можно откатить восстановлением исходного файла из копии. При сложном динамическом SQL полезно изолировать короткий запрос к тестовой таблице, чтобы исключить не относящиеся к делу условия и порядок формирования текста.

#Проверяемый пример и команды

PHP
Фрагмент вставляется только в существующий тестовый скрипт с настроенным $pdo и таблицей users. Он демонстрирует исправленные уникальные метки, а не готовый сценарий подключения. Результат — массив строк, соответствующих фильтру.
<?php
// $pdo — уже настроенное PDO-подключение к тестовой базе.
// Таблица users с колонками name и email должна существовать.
$term = 'anna@example.org';
$sql = 'SELECT id, name FROM users WHERE name = :term_name OR email = :term_email';
$stmt = $pdo->prepare($sql);
$stmt->execute([
    'term_name' => $term,
    'term_email' => $term,
]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
Linux · Терминал (Bash)Команда
В терминале с файлом, содержащим PHP-фрагмент и реальную инициализацию $pdo. Проверяется синтаксис, SQL-поведение требует тестовой БД.
php -l query-example.php

#Проверка исправления и действия при неудаче

Исправление подтверждено, когда запрос с двумя разными именованными метками успешно выполняется при нативной подготовке и выводит ожидаемые строки. Если HY093 сохраняется, проверьте все метки в динамическом SQL и не переводите рабочее подключение на эмуляцию без отдельного обоснования.

Источники и обновления

Последнее обновление статьи: 2 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.