Почему запрос в 1С возвращает пустые данные из виртуальной таблицы и как правильно настроить соединение?

Программист 1С v8.3 (Обычные формы) Управленческий учет
← На главную

Работа с запросами в системе 1С:Предприятие 8 — это фундаментальный навык для любого разработчика. Однако даже опытные специалисты иногда сталкиваются с ситуацией, когда запрос, который кажется логически верным, возвращает пустой результат или пустые колонки из присоединенных таблиц. Особенно часто это происходит при использовании виртуальных таблиц (Обороты, Остатки) и временных таблиц. В данной статье мы подробно разберем типичные ошибки, представленные в обсуждении, проанализируем причины их возникновения и найдем оптимальные способы их решения.

Разбор основной ошибки: Несовпадение типов данных при соединении

Одной из самых коварных ошибок, упомянутых в обсуждении, является попытка соединения таблиц по полям с разными типами данных. Давайте проанализируем фрагмент кода из исходного сообщения:

|ПО | (РаботаОбороты.ПришедшийПоПриглашениюОборот = ВремТабКод.Код)

Разберем ситуацию подробно. Поле ПришедшийПоПриглашениюОборот является ресурсом регистра накопления, который в виртуальной таблице Обороты всегда имеет числовой тип (число). В то же время поле Код из временной таблицы (созданной на основе физической таблицы регистра) является строкой. Важно помнить: в системе 1С (и в большинстве СУБД) сравнение числа со строкой в условии соединения ПО всегда будет давать результат "Ложь" (False). В итоге левое соединение не находит соответствий, и данные из правой таблицы (временной) приходят пустыми (NULL).

Выясним причину, почему так делать нельзя. Для успешного соединения необходимо использовать поля-идентификаторы, имеющие одинаковый тип данных. Обычно это ссылка на объект (например, СправочникСсылка.Работы) или уникальный идентификатор, если речь идет об обмене данными. Рассмотрим, как это должно выглядеть правильно:

|ПО | РаботаОбороты.Работа = ВремТабКод.Работа

Оптимизация фильтрации в виртуальных таблицах

Проанализируем еще одну критическую ошибку в представленном запросе. Автор использует конструкцию ГДЕ для фильтрации данных виртуальной таблицы:

Запрос.Текст = Запрос.Текст + " |ГДЕ | РаботаОбороты.Прод = &Прод";

Рассмотрим, почему такой подход считается грубой ошибкой производительности. Когда мы используем предложение ГДЕ после выбора из виртуальной таблицы, система 1С сначала выполняет обращение к СУБД для получения всех записей за указанный период, сохраняет их во временной памяти и только потом "отсеивает" лишние данные по условию Прод = &Прод. Если в базе миллионы записей, такой запрос может привести к зависанию системы.

Правильным решением будет использование параметров виртуальной таблицы. Виртуальные таблицы — это не просто таблицы в базе, а мощный механизм, который умеет выполнять фильтрацию на уровне SQL-запроса к итогам. Передадим условие в четвертый параметр таблицы Обороты:


|ИЗ
| РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, , Прод = &Прод) КАК РаботаОбороты

В этом случае СУБД получит команду выбрать только те записи, которые уже соответствуют фильтру, что значительно ускорит формирование отчета.

Использование оператора ПОДОБНО для поиска по части строки

В ходе обсуждения возник вопрос: как сделать выборку по части кода, например, отобрать все записи, где код начинается с буквы "Б"? Для этих целей в языке запросов 1С предусмотрен оператор ПОДОБНО.

Разберем синтаксис этого оператора. Он позволяет сравнивать строковое поле с шаблоном, в котором используются специальные символы:

  1. % (процент) — заменяет любое количество произвольных символов.
  2. _ (подчеркивание) — заменяет ровно один произвольный символ.

Посмотрим на пример решения задачи автора. Чтобы выбрать все записи, код которых начинается на "Б", используем условие:

ГДЕ Работа.Код ПОДОБНО "Б%"

Если же нам нужно исключить все записи, начинающиеся на "Б" (как требовалось в сообщении №16), мы применяем отрицание:

ГДЕ НЕ Работа.Код ПОДОБНО "Б%"

Обратите внимание: использование оператора ПОДОБНО с процентом в начале строки (например, "%Б%") отключает использование индексов СУБД, что замедляет запрос. Поиск по началу строки ("Б%") работает гораздо быстрее.

Ошибки группировки в итоговых запросах

В исходном сообщении мы видим странную конструкцию в блоке СГРУППИРОВАТЬ ПО. Автор перечисляет там поля, которые по своей сути являются ресурсами (суммами):


|СГРУППИРОВАТЬ ПО
| РаботаОбороты.УзнавшийИзДругихИсточниковОборот,
| РаботаОбороты.ПришедшийПоПриглашениюОборот

Проанализируем ситуацию: группировка — это процесс схлопывания строк с одинаковыми значениями в одну. Если мы группируем по числовым ресурсам, мы рискуем получить избыточное дробление строк. Правило 1С гласит: все поля, которые мы хотим суммировать, должны быть обернуты в агрегатную функцию (например, СУММА()), а все остальные поля, выбранные в запросе, обязательно должны быть перечислены в секции СГРУППИРОВАТЬ ПО.

Рассмотрим исправленный вариант структуры запроса:


ВЫБРАТЬ
    РаботаОбороты.Период КАК Период,
    ВремТабКод.Код КАК Код,
    СУММА(РаботаОбороты.УзнавшийИзДругихИсточниковОборот) КАК УзнавшийСумма,
    СУММА(РаботаОбороты.ПришедшийПоПриглашениюОборот) КАК ПришедшийСумма
ИЗ
    РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, День, ) КАК РаботаОбороты
ЛЕВОЕ СОЕДИНЕНИЕ 
    ВремТабКод КАК ВремТабКод
ПО 
    РаботаОбороты.Работа = ВремТабКод.Работа
СГРУППИРОВАТЬ ПО
    РаботаОбороты.Период,
    ВремТабКод.Код

Работа с NULL при левом соединении

При использовании ЛЕВОЕ СОЕДИНЕНИЕ важно помнить, что если в правой таблице (в нашем случае ВремТабКод) не найдется записи, соответствующей левой таблице, то все поля из правой таблицы примут значение NULL. Это может привести к ошибкам при выводе в печатную форму или при попытке совершить математические операции.

Выясним, как обезопасить себя от этого. В 1С существует функция ЕСТЬNULL, которая заменяет значение NULL на указанное вами значение по умолчанию. Рассмотрим пример применения:


ВЫБРАТЬ
    РаботаОбороты.Период,
    ЕСТЬNULL(ВремТабКод.Код, "Код не найден") КАК Код,
    ЕСТЬNULL(ВремТабКод.УзнавшийИзДругихИсточниковОборот, 0) КАК ДопОборот

Это гарантирует, что в результате запроса вместо пустоты мы получим либо осмысленную строку, либо ноль, с которым можно проводить расчеты.

Итоги: пошаговый алгоритм проверки запроса

Если ваш запрос возвращает пустые данные или работает некорректно, пройдите по следующим шагам вместе с нами:

  1. Проверьте типы данных в связях: Убедитесь, что вы не сравниваете Ссылку со Строкой или Число со Ссылкой. Это самая частая причина пустых колонок.
  2. Проверьте параметры виртуальных таблиц: Всегда передавайте период и основные фильтры в параметры (в скобках после названия таблицы), а не в ГДЕ.
  3. Анализируйте временные таблицы: Если вы используете временную таблицу, проверьте, заполняется ли она сама по себе. Используйте консоль запросов для тестирования каждого пакета запроса отдельно.
  4. Синтаксис ПОДОБНО: Если вы ищете по коду или наименованию, убедитесь, что кавычки и спецсимволы (%) расставлены верно.
  5. Группировка: Проверьте, что все ресурсы находятся внутри функции СУММА(), а измерения — в блоке СГРУППИРОВАТЬ ПО.

Следуя этим правилам и принципам, вы сможете создавать эффективные и надежные запросы, которые будут корректно обрабатывать данные и обеспечивать высокую производительность ваших решений на платформе 1С:Предприятие 8.

← На главную