Работа с запросами в системе 1С:Предприятие 8 — это фундаментальный навык для любого разработчика. Однако даже опытные специалисты иногда сталкиваются с ситуацией, когда запрос, который кажется логически верным, возвращает пустой результат или пустые колонки из присоединенных таблиц. Особенно часто это происходит при использовании виртуальных таблиц (Обороты, Остатки) и временных таблиц. В данной статье мы подробно разберем типичные ошибки, представленные в обсуждении, проанализируем причины их возникновения и найдем оптимальные способы их решения.
Одной из самых коварных ошибок, упомянутых в обсуждении, является попытка соединения таблиц по полям с разными типами данных. Давайте проанализируем фрагмент кода из исходного сообщения:
|ПО | (РаботаОбороты.ПришедшийПоПриглашениюОборот = ВремТабКод.Код)
Разберем ситуацию подробно. Поле ПришедшийПоПриглашениюОборот является ресурсом регистра накопления, который в виртуальной таблице Обороты всегда имеет числовой тип (число). В то же время поле Код из временной таблицы (созданной на основе физической таблицы регистра) является строкой. Важно помнить: в системе 1С (и в большинстве СУБД) сравнение числа со строкой в условии соединения ПО всегда будет давать результат "Ложь" (False). В итоге левое соединение не находит соответствий, и данные из правой таблицы (временной) приходят пустыми (NULL).
Выясним причину, почему так делать нельзя. Для успешного соединения необходимо использовать поля-идентификаторы, имеющие одинаковый тип данных. Обычно это ссылка на объект (например, СправочникСсылка.Работы) или уникальный идентификатор, если речь идет об обмене данными. Рассмотрим, как это должно выглядеть правильно:
|ПО | РаботаОбороты.Работа = ВремТабКод.Работа
Проанализируем еще одну критическую ошибку в представленном запросе. Автор использует конструкцию ГДЕ для фильтрации данных виртуальной таблицы:
Запрос.Текст = Запрос.Текст + " |ГДЕ | РаботаОбороты.Прод = &Прод";
Рассмотрим, почему такой подход считается грубой ошибкой производительности. Когда мы используем предложение ГДЕ после выбора из виртуальной таблицы, система 1С сначала выполняет обращение к СУБД для получения всех записей за указанный период, сохраняет их во временной памяти и только потом "отсеивает" лишние данные по условию Прод = &Прод. Если в базе миллионы записей, такой запрос может привести к зависанию системы.
Правильным решением будет использование параметров виртуальной таблицы. Виртуальные таблицы — это не просто таблицы в базе, а мощный механизм, который умеет выполнять фильтрацию на уровне SQL-запроса к итогам. Передадим условие в четвертый параметр таблицы Обороты:
|ИЗ
| РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, , Прод = &Прод) КАК РаботаОбороты
В этом случае СУБД получит команду выбрать только те записи, которые уже соответствуют фильтру, что значительно ускорит формирование отчета.
В ходе обсуждения возник вопрос: как сделать выборку по части кода, например, отобрать все записи, где код начинается с буквы "Б"? Для этих целей в языке запросов 1С предусмотрен оператор ПОДОБНО.
Разберем синтаксис этого оператора. Он позволяет сравнивать строковое поле с шаблоном, в котором используются специальные символы:
% (процент) — заменяет любое количество произвольных символов._ (подчеркивание) — заменяет ровно один произвольный символ.Посмотрим на пример решения задачи автора. Чтобы выбрать все записи, код которых начинается на "Б", используем условие:
ГДЕ Работа.Код ПОДОБНО "Б%"
Если же нам нужно исключить все записи, начинающиеся на "Б" (как требовалось в сообщении №16), мы применяем отрицание:
ГДЕ НЕ Работа.Код ПОДОБНО "Б%"
Обратите внимание: использование оператора ПОДОБНО с процентом в начале строки (например, "%Б%") отключает использование индексов СУБД, что замедляет запрос. Поиск по началу строки ("Б%") работает гораздо быстрее.
В исходном сообщении мы видим странную конструкцию в блоке СГРУППИРОВАТЬ ПО. Автор перечисляет там поля, которые по своей сути являются ресурсами (суммами):
|СГРУППИРОВАТЬ ПО
| РаботаОбороты.УзнавшийИзДругихИсточниковОборот,
| РаботаОбороты.ПришедшийПоПриглашениюОборот
Проанализируем ситуацию: группировка — это процесс схлопывания строк с одинаковыми значениями в одну. Если мы группируем по числовым ресурсам, мы рискуем получить избыточное дробление строк. Правило 1С гласит: все поля, которые мы хотим суммировать, должны быть обернуты в агрегатную функцию (например, СУММА()), а все остальные поля, выбранные в запросе, обязательно должны быть перечислены в секции СГРУППИРОВАТЬ ПО.
Рассмотрим исправленный вариант структуры запроса:
ВЫБРАТЬ
РаботаОбороты.Период КАК Период,
ВремТабКод.Код КАК Код,
СУММА(РаботаОбороты.УзнавшийИзДругихИсточниковОборот) КАК УзнавшийСумма,
СУММА(РаботаОбороты.ПришедшийПоПриглашениюОборот) КАК ПришедшийСумма
ИЗ
РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, День, ) КАК РаботаОбороты
ЛЕВОЕ СОЕДИНЕНИЕ
ВремТабКод КАК ВремТабКод
ПО
РаботаОбороты.Работа = ВремТабКод.Работа
СГРУППИРОВАТЬ ПО
РаботаОбороты.Период,
ВремТабКод.Код
При использовании ЛЕВОЕ СОЕДИНЕНИЕ важно помнить, что если в правой таблице (в нашем случае ВремТабКод) не найдется записи, соответствующей левой таблице, то все поля из правой таблицы примут значение NULL. Это может привести к ошибкам при выводе в печатную форму или при попытке совершить математические операции.
Выясним, как обезопасить себя от этого. В 1С существует функция ЕСТЬNULL, которая заменяет значение NULL на указанное вами значение по умолчанию. Рассмотрим пример применения:
ВЫБРАТЬ
РаботаОбороты.Период,
ЕСТЬNULL(ВремТабКод.Код, "Код не найден") КАК Код,
ЕСТЬNULL(ВремТабКод.УзнавшийИзДругихИсточниковОборот, 0) КАК ДопОборот
Это гарантирует, что в результате запроса вместо пустоты мы получим либо осмысленную строку, либо ноль, с которым можно проводить расчеты.
Если ваш запрос возвращает пустые данные или работает некорректно, пройдите по следующим шагам вместе с нами:
ГДЕ.%) расставлены верно.СУММА(), а измерения — в блоке СГРУППИРОВАТЬ ПО.Следуя этим правилам и принципам, вы сможете создавать эффективные и надежные запросы, которые будут корректно обрабатывать данные и обеспечивать высокую производительность ваших решений на платформе 1С:Предприятие 8.