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