Администрирование
SQL-запросы
Рабочая справка по прямым SQL-запросам в коробочном Bitrix24: Application::getConnection, SELECT, UPDATE, транзакции, SQL helper и логирование.
Прямой SQL лучше использовать для диагностики, отчётов и служебных операций. Если есть ORM или нормальное API сущности, сначала стоит рассмотреть их: так меньше риск обойти события, права и бизнес-логику.
Общее понимание
SQL полезен, но в Bitrix24 он легко обходит часть логики модулей.
Когда нужен прямой SQL
- быстрая диагностика данных;
- сложный отчёт по нескольким таблицам;
- поиск проблемных записей;
- служебная миграция данных;
- проверка производительности запроса.
Когда лучше ORM
Если нужно работать с сущностью модуля, у которой есть ORM-таблица или API, лучше
начинать с них. Например, CRM-карточки менять через фабрики или методы CRM, а не
через прямой UPDATE по таблицам.
Выполнение запросов
Основная точка входа — Bitrix\Main\Application::getConnection().
Application::getConnection
<?php
use Bitrix\Main\Application;
/**
* Получает соединение с базой данных.
*/
function fetchDatabaseConnection()
{
return Application::getConnection();
}
$connection = fetchDatabaseConnection(); SELECT
<?php
use Bitrix\Main\Application;
/**
* Получает последние сообщения чата через SQL.
*/
function fetchLastChatMessages(int $chat_id, int $limit): array
{
$connection = Application::getConnection();
$sql_helper = $connection->getSqlHelper();
$chat_id = (int) $chat_id;
$limit = max(1, min((int) $limit, 100));
$sql = "
SELECT
ID,
CHAT_ID,
AUTHOR_ID,
MESSAGE,
DATE_CREATE
FROM b_im_message
WHERE CHAT_ID = {$chat_id}
ORDER BY ID DESC
LIMIT {$limit}
";
$messages = [];
$result = $connection->query($sql);
while ($message = $result->fetch()) {
$messages[] = $message;
}
return $messages;
}
$messages = fetchLastChatMessages($chat_id, 50);
print_r($messages); INSERT, UPDATE, DELETE
Для изменяющих запросов используется queryExecute(). Такие запросы особенно
опасны: они могут обойти проверки, события, таймлайн, историю и роботов.
<?php
use Bitrix\Main\Application;
/**
* Обновляет служебное поле в своей таблице.
*/
function updateCustomItemStatus(int $item_id, string $status): void
{
$connection = Application::getConnection();
$sql_helper = $connection->getSqlHelper();
$item_id = (int) $item_id;
$safe_status = $sql_helper->forSql($status);
$connection->queryExecute("
UPDATE b_custom_item
SET STATUS = '{$safe_status}'
WHERE ID = {$item_id}
");
}
updateCustomItemStatus($item_id, 'done'); Безопасные значения
Строки нужно экранировать через SqlHelper, числа приводить к числам.
<?php
use Bitrix\Main\Application;
/**
* Ищет пользователей по логину.
*/
function fetchUsersByLogin(string $login): array
{
$connection = Application::getConnection();
$sql_helper = $connection->getSqlHelper();
$safe_login = $sql_helper->forSql($login, 255);
$sql = "
SELECT ID, LOGIN, EMAIL
FROM b_user
WHERE LOGIN = '{$safe_login}'
";
$users = [];
$result = $connection->query($sql);
while ($user = $result->fetch()) {
$users[] = $user;
}
return $users;
}
$users = fetchUsersByLogin($login);
print_r($users); Транзакции и диагностика
Если меняется несколько таблиц, лучше использовать транзакцию.
Транзакция
<?php
use Bitrix\Main\Application;
/**
* Выполняет несколько SQL-операций в транзакции.
*/
function updateCustomDataInTransaction(int $item_id, string $status): bool
{
$connection = Application::getConnection();
$sql_helper = $connection->getSqlHelper();
$item_id = (int) $item_id;
$safe_status = $sql_helper->forSql($status);
try {
$connection->startTransaction();
$connection->queryExecute("
UPDATE b_custom_item
SET STATUS = '{$safe_status}'
WHERE ID = {$item_id}
");
$connection->queryExecute("
INSERT INTO b_custom_item_log (ITEM_ID, MESSAGE)
VALUES ({$item_id}, 'Status changed')
");
$connection->commitTransaction();
return true;
} catch (\Throwable $exception) {
$connection->rollbackTransaction();
AddMessage2Log(
[
'message' => $exception->getMessage(),
'item_id' => $item_id,
],
'sql_error'
);
return false;
}
}
$is_updated = updateCustomDataInTransaction($item_id, 'done');
var_dump($is_updated); Логирование SQL
Для ручной диагностики проще сначала логировать сам SQL и параметры, а уже потом выполнять запрос.
<?php
/**
* Пишет SQL в лог.
*/
function writeSqlLog(string $sql, array $parameters = []): void
{
AddMessage2Log(
[
'sql' => $sql,
'parameters' => $parameters,
],
'sql_debug'
);
}