В процессе разработки на платформе 1С:Предприятие часто возникает задача получения какого-либо значения (например, цены, ставки НДС или ответственного лица) из самого свежего документа по определенному аналитическому разрезу (номенклатуре, контрагенту и т.д.). На первый взгляд задача кажется простой, но при работе с языком запросов начинающие разработчики часто сталкиваются с тем, что стандартные конструкции ведут себя не так, как ожидалось.
В этой статье мы подробно разберем, почему простые решения могут не работать, и проанализируем "золотой стандарт" написания таких запросов, который обеспечит точность данных и высокую производительность системы.
Рассмотрим типичную ошибку. Часто предлагают использовать конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 с сортировкой по дате в обратном порядке. Это отлично работает, если вам нужен один-единственный документ во всей базе. Однако, если задача стоит получить последний документ для каждой позиции номенклатуры из списка продаж, этот метод не сработает. Конструкция ВЫБРАТЬ ПЕРВЫЕ ограничивает весь результат запроса одной строкой, а нам нужно получить столько строк, сколько позиций номенклатуры в нашем исходном списке. Если вы только начинаете осваивать теорию, вам может пригодиться шпаргалка по языку запросов, где собраны основные конструкции.
Наиболее эффективный и правильный способ решения этой задачи — использование пакетного запроса. Разберем этот метод по шагам на примере получения ставки НДС из последнего документа ПоступлениеТоваровУслуг. Для разработки и отладки подобных конструкций идеально подходит консоль запросов УФ с полной поддержкой временных таблиц — есть инструментарий для написания и оптимизации запросов.
Шаг 1: Сбор всех подходящих данных во временную таблицу
Сначала нам нужно отобрать все документы поступления, в которых встречается нужная нам номенклатура. Мы сразу выберем номенклатуру, дату документа и саму ссылку на документ. Важно на этом этапе отсечь лишние данные, например, помеченные на удаление или непроведенные документы. К слову, в современных версиях платформы (8.3.25+) появились новые возможности, связанные с добавлением данных в существующую временную таблицу, что открывает дополнительные сценарии оптимизации сложных расчетов.
ВЫБРАТЬ
ПоступлениеТовары.Номенклатура КАК Номенклатура,
ПоступлениеТовары.Ссылка.Дата КАК Дата,
ПоступлениеТовары.Ссылка КАК Ссылка
ПОМЕСТИТЬ втВсеПоступления
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТовары
ГДЕ
ПоступлениеТовары.Ссылка.Проведен = ИСТИНА
И ПоступлениеТовары.Номенклатура В (&СписокНоменклатуры)
;
Шаг 2: Поиск максимальной даты для каждой позиции
Проанализируем полученную таблицу. В ней может быть множество записей по одной и той же номенклатуре. Нам нужно оставить только одну — самую позднюю. Для этого мы используем агрегатную функцию МАКСИМУМ и группировку по номенклатуре.
ВЫБРАТЬ
втВсеПоступления.Номенклатура КАК Номенклатура,
МАКСИМУМ(втВсеПоступления.Дата) КАК МаксДата
ПОМЕСТИТЬ втМаксимальныеДаты
ИЗ
втВсеПоступления КАК втВсеПоступления
СГРУППИРОВАТЬ ПО
втВсеПоступления.Номенклатура
;
Шаг 3: Соединение для получения итоговых данных
Теперь, когда у нас есть пары "Номенклатура - Последняя дата", мы можем соединить эту таблицу обратно с исходными данными документов, чтобы вытащить нужную нам ставку НДС — для этой задачи есть обработка получения цены из последнего документа закупки.
ВЫБРАТЬ
втМаксимальныеДаты.Номенклатура КАК Номенклатура,
ПоступлениеТовары.СтавкаНДС КАК СтавкаНДС
ИЗ
втМаксимальныеДаты КАК втМаксимальныеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТовары
ПО втМаксимальныеДаты.Номенклатура = ПоступлениеТовары.Номенклатура
И втМаксимальныеДаты.МаксДата = ПоступлениеТовары.Ссылка.Дата
ГДЕ
ПоступлениеТовары.Ссылка.Проведен = ИСТИНА
Выясним одну важную деталь: в 1С документы могут иметь абсолютно одинаковую дату (с точностью до секунды). Если в один и тот же момент времени было введено два документа поступления по одной номенклатуре, наше соединение из Шага 3 "раздвоит" результат — мы получим две строки вместо одной.
Чтобы этого избежать, профессиональные разработчики используют связку Дата + Ссылка. Поскольку Ссылка (GUID документа) уникальна, мы можем найти максимум по ссылке среди документов с одинаковой максимальной датой. Это гарантирует нам получение ровно одной записи.
Рассмотрим более совершенную схему пакета запросов:
МАКСИМУМ(Дата) по каждой номенклатуре.ВТ_Даты с таблицей документов и находим МАКСИМУМ(Ссылка) для этой максимальной даты.ВТ_Ссылки с данными документа по полю Ссылка.Проанализируем еще одну ситуацию: что если в одном и том же (последнем) документе одна и та же номенклатура указана в двух разных строках (например, с разной ценой или просто по ошибке)? В этом случае запрос снова выдаст две строки.
Чтобы этого не произошло, при получении финальных данных (Ставки НДС) рекомендуется также использовать группировку или функцию МАКСИМУМ. Например, выберем МАКСИМУМ(СтавкаНДС) или МАКСИМУМ(НомерСтроки), чтобы "схлопнуть" записи до одной.
Работа с табличными частями документов напрямую в больших базах может быть медленной. Если вы столкнулись с падением скорости, полезно выполнить комплексный замер производительности контура 1С для поиска узких мест. Также стоит обратить внимание на следующие советы по оптимизации:
Номенклатура в табличной части проиндексировано (свойство "Индексировать" в конфигураторе).Дата >= &НачалоГода). Это значительно ускорит работу СУБД.СрезПоследних, которая работает во много раз быстрее сложных запросов к документам.Используя предложенный метод временных таблиц с учетом уникальности ссылок и проверкой статуса проведения, вы получите надежный механизм извлечения актуальных данных, который будет корректно работать даже в условиях интенсивного документооборота.