Почему данные в динамическом списке отличаются от консоли запросов и как это исправить

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

Разработка интерфейсов на управляемых формах 1С часто преподносит сюрпризы, когда идеально работающий в консоли запрос начинает выдавать странные цифры в динамическом списке. Ситуация, когда вместо ожидаемой суммы 690 рублей система отображает 5070, является классическим симптомом внутренних механизмов работы платформы. В этой статье мы подробно разберем, почему динамический список «врет», и как привести его данные в порядок.

Анализ проблемы: почему возникают расхождения

Прежде всего, разберем ситуацию, описанную в коде. Разработчик пытается вычислить сумму по складским ордерам в списке заказов клиентов. Для этого используются временные таблицы, в которых группируются данные по номенклатуре и распоряжениям, а затем результат соединяется с основной таблицей заказов. В консоли запросов такой подход работает, так как она выполняет запрос «как есть». Динамический список же — это сложный объект, который трансформирует исходный текст запроса перед отправкой на СУБД.

Рассмотрим основные причины, по которым данные могут «размножаться» или искажаться:

  1. Дублирование строк при соединениях. Это самая частая причина. Если в табличной части Документ.ЗаказКлиента.Товары одна и та же номенклатура встречается дважды (например, с разными характеристиками, складами или просто в разных строках), то при соединении по полям Номенклатура и Ссылка данные из временной таблицы прибавятся к результату столько раз, сколько строк с этой номенклатурой найдено в заказе.
  2. Особенности работы платформы с временными таблицами. Динамический список оптимизирован для постраничного вывода. При использовании сложных цепочек ПОМЕСТИТЬ ВТ платформа может некорректно накладывать условия отбора или группировки, что приводит к непредсказуемым итогам.
  3. Влияние RLS (Row Level Security). Права доступа на уровне записей автоматически добавляют в запрос скрытые условия ГДЕ. Если у пользователя ограничены права на РасходныйОрдерНаТовары, но есть права на ЗаказКлиента, расчет итогов может «посыпаться» из-за специфики вложенных соединений.

Шаг 1: Диагностика исполняемого запроса

Чтобы понять, какой именно запрос уходит на сервер базы данных, недостаточно просто смотреть в конфигуратор. Выясним, как платформа модифицировала наш текст. Для этого воспользуемся встроенными методами динамического списка в модуле формы.

Разберем пример кода для получения реального текста запроса:


// В процедуре ПриСозданииНаСервере или через отдельную команду
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();

КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

// Теперь в МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос содержится финальный текст
ТекстРеальногоЗапроса = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;
Сообщить(ТекстРеальногоЗапроса);

Проанализируем полученный текст. Скорее всего, вы увидите, что платформа добавила дополнительные поля (например, ссылки на версии данных) и обернула ваш запрос в еще один уровень выборки. Если в этом тексте вы видите дублирующиеся условия СОЕДИНЕНИЕ, причина найдена.

Шаг 2: Проверка на «жесткие» данные

Если вы сомневаетесь, что проблема в данных, а не в коде, используем метод «заглушки». В тексте запроса динамического списка заменим вычисляемое поле на константу:


ВЫБРАТЬ
    ДокументЗаказКлиента.Ссылка КАК Ссылка,
    ...
    11111 КАК СуммаОрдера
ИЗ
    Документ.ЗаказКлиента КАК ДокументЗаказКлиента

Если после этого в списке везде отображается «11111», значит, динамический список работает штатно и проблема исключительно в логике соединений внутри вашего SQL-запроса. Если же даже константа не отображается или отображается не везде — проблема в кэшировании формы или программном переопределении запроса.

Шаг 3: Исправление логики соединений

Вернемся к примеру автора. Проблема в том, что расчет суммы идет через соединение с табличной частью документа. Рассмотрим правильный подход: расчет должен производиться строго до уровня уникального ключа (в данном случае — ссылки на Заказ Клиента), чтобы исключить «раздувание» строк.

Рекомендуется переписать запрос следующим образом:

  1. Сначала собрать все данные по ордерам в разрезе только Распоряжения (без номенклатуры, если это возможно для расчета суммы).
  2. Если цена берется из заказа, сначала вычислить стоимость каждой строки ордера, а затем сгруппировать их внутри временной таблицы до уровня Ссылка заказа.
  3. В основном запросе соединяться с временной таблицей ЛЕВЫМ СОЕДИНЕНИЕМ только по полю Ссылка.

Посмотрим на пример оптимизированного участка кода:


// ВТ1: Получаем количество по ордерам в разрезе Номенклатура + Заказ
ВЫБРАТЬ
    ТЧ.Распоряжение КАК Заказ,
    ТЧ.Номенклатура КАК Номенклатура,
    СУММА(ТЧ.Количество) КАК КолОрдер
ПОМЕСТИТЬ ВТ_Ордера
ИЗ
    Документ.РасходныйОрдерНаТовары.ТоварыПоРаспоряжениям КАК ТЧ
ГДЕ
    ТЧ.Ссылка.Проведен
СГРУППИРОВАТЬ ПО
    ТЧ.Распоряжение, ТЧ.Номенклатура;

////////////////////////////////////////////////////////////////
// ВТ2: Считаем сумму, соединяясь с ценами из Заказа
ВЫБРАТЬ
    ВТ.Заказ КАК Заказ,
    СУММА(ВТ.КолОрдер * ТЧ_Заказа.Цена) КАК СуммаОрдераИтого
ПОМЕСТИТЬ ВТ_ИтоговыеСуммы
ИЗ
    ВТ_Ордера КАК ВТ
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента.Товары КАК ТЧ_Заказа
    ПО ВТ.Заказ = ТЧ_Заказа.Ссылка И ВТ.Номенклатура = ТЧ_Заказа.Номенклатура
СГРУППИРОВАТЬ ПО
    ВТ.Заказ;

Обратите внимание на СГРУППИРОВАТЬ ПО ВТ.Заказ в последней таблице. Это гарантирует, что на выходе для каждого заказа будет ровно одна строка с суммой, независимо от количества позиций номенклатуры.

Шаг 4: Избегаем использования временных таблиц в ДС

Хотя временные таблицы (ВТ) разрешены в динамических списках, опытные разработчики рекомендуют их избегать, если запрос планируется использовать в списках с большим количеством данных. Платформа 1С может выполнять запрос к ВТ при каждом скроллинге, что негативно сказывается на производительности.

Альтернативный вариант — использование вложенных запросов. Несмотря на то, что в обычном программировании вложенные запросы считаются менее читаемыми, для оптимизатора динамического списка они часто «прозрачнее», так как позволяют платформе эффективнее встраивать условия отборов в подзапросы.

Рекомендации по стабильной работе динамических списков

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

Проанализировав ситуацию с «ерундой» в суммах, мы выяснили, что чудо обычно объясняется математикой соединений. Используйте СГРУППИРОВАТЬ на самом раннем этапе формирования данных и всегда проверяйте исполняемый макет компоновки — это сэкономит часы отладки.

← На главную