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