Разработчики, работающие с платформой 1С:Предприятие 7.7, часто сталкиваются с загадочным поведением так называемых «черных» (штатных) запросов при переходе с DBF на SQL версию. Одной из самых распространенных проблем является ситуация, когда пользовательская функция, вызванная внутри текста запроса, в DBF-варианте отрабатывает корректно, а в SQL-версии всегда возвращает 0. Давайте разберем причины этого явления и рассмотрим способы решения этой задачи.
Для начала проанализируем, как работает штатный механизм запросов в 1С 7.7. Когда мы используем объект Запрос, платформа интерпретирует наш код. В случае с DBF-базой 1С сама перебирает записи таблиц и для каждой строки может вызвать функцию, написанную на встроенном языке 1С. Однако в SQL-версии поведение меняется, особенно при использовании метода ВключитьSQL(1).
Рассмотрим механизм работы ВключитьSQL(1):
SELECT), который отправляется на сервер Microsoft SQL Server.КолвоПлюс(Колво, 1) в текст SQL-запроса, он просто подставляет значение по умолчанию для числового типа — 0.Важный нюанс: даже если вы явно не вызываете Запрос.ВключитьSQL(1), в SQL-версии платформы этот режим часто включается неявно для ускорения выборки данных из регистров. Именно поэтому функция «перестает работать» сразу после миграции базы на SQL.
Самый простой, но «болезненный» с точки зрения производительности способ — это принудительное отключение трансляции запроса в SQL. Для этого используется метод ВключитьSQL(0).
Рассмотрим пример кода:
Запрос = СоздатьОбъект("Запрос");
// Принудительно отключаем выполнение на стороне SQL-сервера
Запрос.ВключитьSQL(0);
ТекстЗапроса = "
|Ном = Регистр.ПартииНаличие.Номенклатура;
|Колво = Регистр.ПартииНаличие.Количество;
|Функция КолвоПлюс = Сумма(КолвоПлюс(Колво, 1));
|Группировка Ном;
|";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
// Здесь функция КолвоПлюс будет возвращать корректные значения
КонецЕсли;
Анализ ситуации: При ВключитьSQL(0) платформа будет скачивать данные из SQL-таблиц во временные локальные файлы и обрабатывать их построчно силами собственного движка. Это заставит функцию работать, но скорость выполнения запроса может упасть в 10–20 раз на больших объемах данных. Это решение подходит только для редких отчетов или маленьких справочников.
Если нам важна скорость, мы можем разделить процесс на два этапа: получение сырых данных быстрым SQL-запросом и последующий расчет в 1С. Проанализируем этот подход:
Колво).ТаблицаЗначений с помощью метода Выгрузить(ТЗ).Посмотрим на пример реализации:
Запрос = СоздатьОбъект("Запрос");
Запрос.ВключитьSQL(1); // Оставляем скорость
ТекстЗапроса = "
|Ном = Регистр.ПартииНаличие.Номенклатура;
|Колво = Регистр.ПартииНаличие.Количество;
|Функция КонОстКолво = КонОст(Колво);
|Группировка Ном;
|";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗ);
// Добавляем колонку для нашего вычисляемого значения
ТЗ.НоваяКолонка("КолвоПлюс");
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
// Вызываем функцию 1С для каждой строки таблицы
ТЗ.КолвоПлюс = КолвоПлюс(ТЗ.КонОстКолво, 1);
КонецЦикла;
КонецЕсли;
Этот метод сохраняет преимущества высокой скорости SQL-запроса и позволяет использовать любую сложную логику 1С.
Для профессиональной разработки в среде 1С 7.7 на SQL стандартом де-факто является использование внешних компонент, таких как 1CPP.dll. Прямые запросы позволяют писать код непосредственно на языке T-SQL, минуя ограничения штатного построителя 1С.
Разберем, как реализовать ту же логику КолвоПлюс(Колво, 1) через прямой запрос. Вместо функции 1С мы опишем это математическое действие прямо в тексте запроса.
Пример использования прямой выборки через объект ODBCRecordset:
// Требуется наличие 1cpp.dll
ЗапросSQL = СоздатьОбъект("ODBCRecordset");
Текст = "
|SELECT
| Рег.ID [Ном $Справочник.Номенклатура],
| SUM(Рег.Quantity) as [Колво],
| SUM(Рег.Quantity + 1) as [КолвоПлюс] -- Логика функции на стороне SQL
|FROM
| $Регистр.ПартииНаличие as Рег
|GROUP BY
| Рег.ID
|";
ТЗ = ЗапросSQL.ВыполнитьИнструкцию(Текст);
Преимущества данного метода:
CASE WHEN, ISNULL, CAST и другие возможности SQL.Если ваш запрос в 1С 7.7 на SQL выдает нули вместо результатов функций, помните: штатный запрос 1С не умеет передавать ваши функции серверу SQL. Для решения проблемы мы рекомендуем:
ВключитьSQL(1) только в крайнем случае, когда объем данных минимален и скорость не критична.