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