При разработке отчетов и обработок в 1С часто возникает задача определить документ поступления, предшествующий документу реализации. Ситуация усложняется, когда пользователи проводят документы «задним числом» на одну и ту же дату и секунду (например, 02.12.2016 23:59:59). В этом случае стандартный запрос с условием Период <= &Дата и сортировкой по убыванию периода может вернуть некорректный результат или не найти нужную запись.
Разберем причины возникновения этой проблемы и рассмотрим надежные способы получения правильного регистратора через язык запросов 1С.
Проанализируем технические особенности работы платформы с датами и записями регистров:
МоментВремени в языке запросов: тип МоментВремени существует только в объектной модели платформы 1С. В тексте запроса нельзя написать условие вида ТоварыНаСкладах.МоментВремени < &МоментВремени — СУБД оперирует исключительно полями таблиц базы данных.Период, условие УПОРЯДОЧИТЬ ПО Период УБЫВ не гарантирует строгий порядок строк. СУБД возвращает записи с одинаковым периодом в произвольном порядке, поэтому конструкция ВЫБРАТЬ ПЕРВЫЕ 1 может вернуть случайный документ.Регистратор имеет составной ссылочный тип. При обращении к реквизитам регистратора без ограничения типов платформа формирует неявные левые соединения (LEFT JOIN) со всеми таблицами документов, являющихся регистраторами регистра, что снижает производительность.Рассмотрим, как правильно сравнить положение документов на оси времени внутри текста запроса. Для этого сопоставим даты и ссылки документов, добавив полную детерминированную сортировку:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ТоварыНаСкладах.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
|ГДЕ
| ТоварыНаСкладах.Номенклатура = &Номенклатура
| И ТоварыНаСкладах.ВидДвижения = &ВидДвижения
| И (ТоварыНаСкладах.Период < &ДатаДокумента
| ИЛИ (ТоварыНаСкладах.Период = &ДатаДокумента
| И ТоварыНаСкладах.Регистратор < &ТекущийРегистратор))
| И НЕ ТоварыНаСкладах.Регистратор ССЫЛКА Документ.ПеремещениеТоваров
|
|УПОРЯДОЧИТЬ ПО
| ТоварыНаСкладах.Период УБЫВ,
| ТоварыНаСкладах.Регистратор УБЫВ,
| ТоварыНаСкладах.НомерСтроки УБЫВ";
Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
Запрос.УстановитьПараметр("ВидДвижения", ВидДвиженияНакопления.Приход);
Запрос.УстановитьПараметр("ДатаДокумента", ДокументСсылка.Дата);
Запрос.УстановитьПараметр("ТекущийРегистратор", ДокументСсылка);
РезультатЗапроса = Запрос.Выполнить();
Посмотрим на ключевые особенности этого подхода:
ТоварыНаСкладах.Период = &ДатаДокумента И ТоварыНаСкладах.Регистратор < &ТекущийРегистратор позволяет однозначно отсечь записи, созданные текущим или более поздними документами в рамках той же секунды.Период, Регистратор и НомерСтроки обеспечивает строго предсказуемый результат работы инструкции ВЫБРАТЬ ПЕРВЫЕ 1.Разберем альтернативный вариант через виртуальную таблицу Обороты с периодичностью Регистратор. Виртуальные таблицы платформы 1С поддерживают передачу объекта Граница, что исключает необходимость ручного сравнения дат в условиях запроса.
ГраницаПоиска = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Исключая);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ТоварыНаСкладахОбороты.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Обороты(
| ,
| &ПериодОкончания,
| Регистратор,
| Номенклатура = &Номенклатура
| И ВНаличииПриход > 0
| И НЕ Регистратор ССЫЛКА Документ.ПеремещениеТоваров) КАК ТоварыНаСкладахОбороты
|
|УПОРЯДОЧИТЬ ПО
| ТоварыНаСкладахОбороты.Период УБЫВ,
| ТоварыНаСкладахОбороты.Регистратор УБЫВ";
Запрос.УстановитьПараметр("ПериодОкончания", ГраницаПоиска);
Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
РезультатЗапроса = Запрос.Выполнить();
Проанализируем преимущества работы с виртуальной таблицей:
Граница: передача ВидГраницы.Исключая гарантирует, что платформа автоматически исключит движения самого документа расхода и любые движения, находящиеся позже на шкале времени.ВидДвижения или перечисления всех возможных типов документов (ПоступлениеТоваровУслуг, ВводНачальныхОстатков, ПрочееОприходованиеТоваров) достаточно наложить условие на ресурс оборота ВНаличииПриход > 0 (или КоличествоПриход > 0 в зависимости от конфигурации).Обратите внимание: в конфигурациях линейки УТ 11 регистр ТоварыНаСкладах служит исключительно для учета складских остатков в штуках и не предназначен для партионного учета. Если задача состоит в сопоставлении списания и поступления по методу ФИФО или по конкретным поставкам, рекомендуется использовать специализированные регистры партионного учета (например, ДетализацияПартийТоваровДляНДС или ПартииТоваровНаСкладах), где партия фиксируется как отдельное измерение.