При анализе сложных запросов в платформах 1С нередко можно встретить логические условия вида тбРегВзаимОстатки.РасчетныйДокумент <= тбРегВыпУсл.ДокументСобытия. На первый взгляд разработчику может показаться, что система автоматически сравнивает документы по их дате или моменту времени. Однако на практике результаты такого отбора оказываются непредсказуемыми. Разберем подробнее, как платформа 1С и СУБД обрабатывают сравнение ссылочных типов данных и как правильно решать подобные задачи.
В языке запросов 1С ссылки на документы или справочники не являются привычными датами или числами. Ссылка — это составной объект. При трансляции запроса к системе управления базами данных (Microsoft SQL Server, PostgreSQL и др.) платформа 1С преобразует сравнение ссылочных полей в побайтовое сравнение нескольких внутренних служебных колонок:
Проанализируем ситуацию, когда сравниваются документы разных видов (например, Документ.ПриходныйКассовыйОрдер и Документ.РеализацияТоваровУслуг). В этом случае СУБД сравнивает значение поля _RTRef. Документ того вида, чей внутренний номер метаданных меньше, всегда будет считаться «меньше» другого документа, независимо от реальной даты их создания, номеров и физического порядка проведения.
Если же сравниваются документы одного вида, поле _RTRef совпадает, и СУБД переходит к побайтовому сравнению 16 байт поля _RRRef. Уникальные идентификаторы формируются платформой по определенным алгоритмам, но они не гарантируют строгого соответствия реальной хронологии. Если документы создавались последовательно в одном сеансе, их GUID могут располагаться по порядку. Однако при работе в параллельных сеансах или при загрузке данных порядок GUID становится псевдослучайным.
Рассмотрим пример кода из реальной практики, где разработчик попытался связать таблицы по условию сравнения ссылок:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
тбРегВзаимОстатки.Организация,
тбРегВзаимОстатки.Контрагент,
тбРегВзаимОстатки.РасчетныйДокумент,
тбРегВыпУсл.ДокументСобытия
ИЗ
тбРегВзаимОстатки КАК тбРегВзаимОстатки
ЛЕВОЕ СОЕДИНЕНИЕ тбРегВыпУсл КАК тбРегВыпУсл
ПО тбРегВзаимОстатки.Организация = тбРегВыпУсл.Организация
И тбРегВзаимОстатки.Контрагент = тбРегВыпУсл.Контрагент
И (тбРегВзаимОстатки.РасчетныйДокумент <= тбРегВыпУсл.ДокументСобытия)
Использование операторов <, <=, >, >= для ссылочных типов с целью ограничить выборку по времени — это явная архитектурная ошибка. Результат выполнения такого запроса зависит только от внутренних идентификаторов СУБД, но никак не от реквизита Дата.
Выясним, как правильно решить задачу сопоставления документов по хронологии в языке запросов 1С.
Если реквизит имеет составной ссылочный тип (например, РасчетныйДокумент), вызов поля Дата через точку напрямую невозможен или приводит к NULL. Чтобы обратиться к дате, необходимо явно привести ссылку к конкретному типу документа с помощью конструкции ВЫРАЗИТЬ:
ВЫБРАТЬ
ВЫБОР
КОГДА Таблица.РасчетныйДокумент ССЫЛКА Документ.ПоступлениеТоваровУслуг
ТОГДА ВЫРАЗИТЬ(Таблица.РасчетныйДокумент КАК Документ.ПоступлениеТоваровУслуг).Дата
КОГДА Таблица.РасчетныйДокумент ССЫЛКА Документ.ОтчетКомиссионера
ТОГДА ВЫРАЗИТЬ(Таблица.РасчетныйДокумент КАК Документ.ОтчетКомиссионера).Дата
ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1)
КОНЕЦ КАК ДатаРасчетногоДокумента
ИЗ
РегистрНакопления.Взаиморасчеты КАК Таблица
Тип МоментВремени существует только во встроенном языке 1С и недоступен внутри запросов. Если требуется сравнить две точки на оси времени с точностью до позиции документа внутри секунды, используют составное условие по дате и ссылке:
ГДЕ
(Документ1.Дата < Документ2.Дата)
ИЛИ (Документ1.Дата = Документ2.Дата И Документ1.Ссылка <= Документ2.Ссылка)
В этом условии оператор <= для ссылок используется исключительно как «разрешитель ничьей» (tie-breaker), когда даты документов полностью совпадают с точностью до секунды. Это обеспечивает детерминированную и стабильную сортировку выборки.
Если алгоритм требует точной проверки объекта МоментВремени, разберем порядок действий на встроенном языке:
Ссылка.ПолучитьМоментВремени().МоментВремени стандартными операторами языка 1С.Подводя итог: никогда не используйте прямое сравнение ссылок в запросах для определения того, какой документ был оформлен раньше или позже. Всегда сравнивайте реквизиты Дата, при необходимости ограничив составные типы оператором ВЫРАЗИТЬ.