Запросы к БД через PDO
В MODX предусмотрены 2 основных способа работы с базой данных — через xPDO и через PDO. По первому способу информации достаточно много. Как правило, разработчики работают с БД именно через xPDO. Но бывают такие случаи, когда нужно использовать PDO. Например, быстро добавить какое-нибудь значение в свою таблицу или написать сложный запрос. В этом случае разработчик должен понимать, что он делает, потому что в связи между таблицами, в отличие от xPDO, не работают и могут возникнуть проблемы со ссылочной целостностью.
Основные методы PDO — xPDO::query($sql)
, xPDO::exec($sql)
и xPDO::prepare()/PDOStatement::execute()
. По ним и пробежимся.
xPDO::exec($sql)
Этот метод запускает SQL запрос на выполнение и возвращает количество строк, задействованых в ходе его выполнения. Данные в SQL запросе должны быть правильно экранированы.
// Удаляем все неактивные записи из произвольной таблицы $sql = "DELETE FROM myTable WHERE active = 0"; $count = $modx->exec($sql); // Получим количество удаленных записей print("Удалено $count записей.");
Важно запомнить, что этот метод возвращает только количество строк. Т.е. оператор SELECT в данном случае используется, как если бы запрос был SELECT COUNT(*).
$sql = "SELECT * FROM modx_users WHERE sudo = 1"; $count = $modx->exec($sql); // Получим количество администраторов с правами SUDO print("Количество пользователей с неограниченными правами - $count.");
Если нужно получить результат выборки, то нужно использовать методы, о которых я расскажу дальше.
xPDO::query($sql)
Этот метод выполняет SQL запрос и возвращает результирующий набор в виде объекта PDOStatement. Опять же, данные должны быть уже подготовлены и экранированы. Иначе можно пропустить SQL инъекцию.
PDO::query() возвращает объект PDOStatement или FALSE, если запрос выполнить не удалось.
$sql = "SELECT * FROM modx_users WHERE active = 1"; // Вариант 1. $statement = $modx->query($sql); $users = $statement->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $user) { print $user['username'] .'<br/>'; } // Вариант 2. Если не нужно зачитывать данные в массив foreach ($modx->query($sql) as $user) { print $user['username'] .'<br/>'; }
Узнать количество записей, задействованных в последнем запросе, можно с помощью специального метода PDOStatement::rowCount()
.
$count = $statement->rowCount();
Если в запросе используются переменные или запрос планируется использовать несколько раз, то для этих случаев подойдут подготовленные выражения (prepared statements).
xPDO::prepare($sql) и PDOStatement::execute()
Смысл подготовленных выражений заключается в том, что заранее подготавливается шаблон SQL запроса, который при запуске настраивается с помощью специальных плейсхолдеров. Преимущества подготовленного запроса:
- Не нужно подготавливать запрос каждый раз. Немного повышает производительность системы.
- Запрос не нужно экранировать, драйвер БД может делает это автоматически — что значительно снижает риск получить SQL инъекцию.
PDO поддерживает 2 вида плейсхолдеров — позиционные (?), для которых важен порядок передаваемых переменных, и именованные (:name), для которых порядок не важен.
// 1. Позиционный плейсхолдер $sql = 'SELECT name FROM modx_users WHERE email = ?'; // Подготавливаем шаблон SQL запроса $statement = $modx->prepare($sql); // Выполняем запрос подставляя данные if ( $statement->execute(array($_GET['email'])) ) { $result = $statement->fetchAll(PDO::FETCH_ASSOC); } // 2. Именованный плейсхолдер $sql = 'SELECT name FROM modx_users WHERE email = :email'; // Подготавливаем шаблон SQL запроса $statement = $modx->prepare($sql); // Выполняем запрос подставляя данные if ( $statement->execute(array('email'=>$_GET['email'])) ) { $result = $statement->fetchAll(PDO::FETCH_ASSOC); }
При таком подходе невозможно подсунуть SQL инъекцию, даже если подставлять необработанные данные (см. пример). Кроме того, подготовив один раз запрос, можно несколько раз выполнить метод execute() подставляя разные значения.
Ещё передать данные в подготовленный запрос можно используя специальные методы PDOStatement::bindParam()
и PDOStatement::bindValue()
. Подробнее про них можно прочитать в официальной документации.
Комментарии ()
Вы должны авторизоваться, чтобы оставлять комментарии.
Помогите сформировать запрос такого характера:
1. У меня есть таблица с некими записями, в которой есть поля: id (AI), vid, pid, aid
2. Мне нужно получить следующую запрись из БД, зная о текущей все (id, vid, pid, aid), но чтобы у следующей записи последние 3 параметра (vid, pid, aid) были такие же, как у текущей.
3. Сложность для меня в том, что это не обязательно может быть соседний id, может он вообще будет через десяток записей.
Прошу помощи с формированием запроса))
Далее, нужна одна из следующих по порядку записей, а не предыдущая. Т.е. у неё id должен быть больше id текущей. Значит в WHERE нужно добавить условие неравенства.
Ну и наконец, запись нужна только одна. Поэтому нужно ограничить запрос через LIMIT. И обязательно нужно удостовериться, что это именно следующая запись, а не вторая или третья по очереди. Для чего нужно сделать соответствующую сортировку ORDER BY.
Осталось всё это совместить.
А следом попробовать сформировать этот запрос через xPDO.
Может, вы в курсе, как решить эту задачу?
Столкнулся с задачей импорта из кастомного csv данных в свою таблицу, сделал через INSERT INTO… VALUES… ON DUPLICATE KEY UPDATE. Работает, но долго, как по мне.
Для того, чтобы достать id последней вставленной или обновленной записи, пользуюсь $modx->lastInsertId($q), все показывает правильно: если запись была, то возвращает ее id, если она новая, то id вставленной записи.
Попробовал перейти на prepared statements до перебора цикла, а дальше при переборе уже
$q->bindValue(1, $dataΎ]);
$q->bindValue(2, $dataΏ]);
…
$q->execute();
Все, на этом id последней вставленной записи ломается: возвращает id больше, чем последний AUTO_INCREMENT в таблице.
Подскажите, пожалуйста, как перевести на PDO, вот такой запрос:
Нужно получить id из таблицы которую создает компонент HybridAuth.
А в чём сложность? Выбирайте любой вариант из статьи.
Можно ли подготовить запрос типа:
Делал функцию, которая выводит инфу с нужно мне таблицы. До этого плейсхолдеры работали предано. Но сейчас почему то вылезает ошибка, о неправильном синтаксисе sql-запроса. Есть подозрения, что для FROM тега плейсходеры не работают. Так как до этого их для WHERE или VALUE и тп., но для такого у меня не было, да и во всех статьях тоже его не трогают
Может ли такое быть? Может уже придется меня подключение PDO, не на прямую в нужно БД, а просто в сам MySQL.
За раннее спасибо.
Я не понимаю, что Вы пытаетесь сделать. Какой запрос у Вас должен получиться в чистом виде? Ваш запрос работать не будет. Он составлен не правильно. В секции FROM нужно указать таблицу. Иначе как MySql будет подготавливать запрос, если он не знает к какой таблице обращаться.