При разработке списков документов в управляемых формах часто возникает задача отобразить процент отгрузки или оплаты непосредственно в строке списка. Однако при составлении произвольного запроса для динамического списка разработчики нередко сталкиваются с ситуацией, когда полностью отгруженные или нулевые заказы пропадают из списка, выдают некорректные проценты или список начинает аварийно завершать работу.
Разберем типичные ошибки при построении таких запросов, выясним их причины и сформируем готовое оптимизированное решение.
Рассмотрим, какие именно ошибки приводят к исчезновению строк или неверному расчету:
Остатки исчезает. В результате исчезает и сам документ из выборки. Чтобы этого избежать, ведущей таблицей должен выступать документ Документ.ЗаказКлиента, к которому левым соединением подключается таблица остатков.Поле = NULL всегда возвращает Ложь (FALSE), так как NULL обозначает отсутствие значения и не может быть равен ничему, даже самому себе. Для проверки необходимо использовать функцию ЕСТЬNULL() или оператор Поле ЕСТЬ NULL.100 вместо суммы документа приводит к неверным числам. Для вычисления доли необходимо находить отношение отгруженной суммы к общей сумме документа и умножать результат на 100.ЗаказыКлиентовОстатки.ЗаказКлиента.Ссылка создает неявное дополнительное соединение с базовой таблицей документа. Поле измерения ЗаказКлиента уже содержит ссылку, поэтому соединять следует напрямую: ЗаказыКлиентовОстатки.ЗаказКлиента.ОсновнаяТаблица может очиститься. Без указания основной таблицы платформа не может определить ключевые поля, отключаются стандартные механизмы динамического считывания, а также контекстные команды списка.Проанализируем структуру правильного запроса. Сначала обеспечим корректное левое соединение и обработку нулевых сумм документа, чтобы исключить ошибку деления на ноль.
Посмотрим на пример логики вычисления процента:
ВЫБРАТЬ
ДокументЗаказ.Ссылка КАК Ссылка,
ДокументЗаказ.Номер КАК Номер,
ДокументЗаказ.Дата КАК Дата,
ДокументЗаказ.СуммаДокумента КАК СуммаДокумента,
ВЫБОР
КОГДА ДокументЗаказ.СуммаДокумента = 0
ТОГДА ВЫБОР
КОГДА ЗаказыОстатки.КоличествоОстаток ЕСТЬ NULL
ТОГДА 100
ИНАЧЕ 0
КОНЕЦ
ИНАЧЕ ВЫРАЗИТЬ((ДокументЗаказ.СуммаДокумента - ЕСТЬNULL(ЗаказыОстатки.СуммаОстаток, 0)) / ДокументЗаказ.СуммаДокумента * 100 КАК ЧИСЛО(5, 2))
КОНЕЦ КАК ПроцентОтгрузки
ИЗ
Документ.ЗаказКлиента КАК ДокументЗаказ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ЗаказыКлиентов.Остатки КАК ЗаказыОстатки
ПО ДокументЗаказ.Ссылка = ЗаказыОстатки.ЗаказКлиента
ГДЕ
ДокументЗаказ.Проведен
Разберем, как работает данная конструкция:
0, проверяется наличие товарного остатка. Отсутствие записи в регистре (ЕСТЬ NULL) говорит о том, что заказ отгружен полностью (100%), иначе выводится 0%.0, из суммы документа вычитается остаток из регистра (с защитой от NULL через ЕСТЬNULL(..., 0)), делится на исходную сумму и умножается на 100.ВЫРАЗИТЬ(... КАК ЧИСЛО(5, 2)) защищает от бесконечных периодических дробей в интерфейсе.Таблица РегистрНакопления.ЗаказыКлиентов.Остатки возвращает данные в разрезе всех измерений (номенклатура, характеристика, склад и т. д.). Если в заказе несколько позиций номенклатуры, левое соединение вернет несколько строк на один документ. В результате в динамическом списке строки заказа начнут двоиться или троиться.
Чтобы избежать дублирования, свернем остатки во вложенном запросе по измерению ЗаказКлиента:
ВЫБРАТЬ
ДокументЗаказ.Ссылка КАК Ссылка,
ДокументЗаказ.Номер КАК Номер,
ДокументЗаказ.Дата КАК Дата,
ДокументЗаказ.СуммаДокумента КАК СуммаДокумента,
ВЫБОР
КОГДА ДокументЗаказ.СуммаДокумента = 0
ТОГДА ВЫБОР
КОГДА СвернутыеОстатки.СуммаОстаток ЕСТЬ NULL
ТОГДА 100
ИНАЧЕ 0
КОНЕЦ
ИНАЧЕ ВЫРАЗИТЬ((ДокументЗаказ.СуммаДокумента - ЕСТЬNULL(СвернутыеОстатки.СуммаОстаток, 0)) / ДокументЗаказ.СуммаДокумента * 100 КАК ЧИСЛО(5, 2))
КОНЕЦ КАК ПроцентОтгрузки
ИЗ
Документ.ЗаказКлиента КАК ДокументЗаказ
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
Остатки.ЗаказКлиента КАК ЗаказКлиента,
СУММА(Остатки.СуммаОстаток) КАК СуммаОстаток
ИЗ
РегистрНакопления.ЗаказыКлиентов.Остатки КАК Остатки
СГРУППИРОВАТЬ ПО
Остатки.ЗаказКлиента
) КАК СвернутыеОстатки
ПО ДокументЗаказ.Ссылка = СвернутыеОстатки.ЗаказКлиента
При внедрении запроса в форму списка обратим внимание на следующие технические моменты:
ОсновнаяТаблица обязательно указываем Документ.ЗаказКлиента. Если платформа блокирует редактирование запроса или ругается на поля, временно снимем флаг «Произвольный запрос», укажем основную таблицу, затем снова включим флаг и вставим текст запроса.ПриПолученииДанныхНаСервере.