В практике программирования на платформе 1С:Предприятие часто возникают задачи, требующие соединения таблиц «самих с собой» или получения данных нарастающим итогом. В старых или специфических решениях можно встретить конструкции вида Документ1.Ссылка < Документ2.Ссылка. У многих разработчиков это вызывает закономерный вопрос: что именно сравнивает платформа? Дату? Время создания? Или что-то иное?
В этой статье мы подробно разберем внутреннюю механику работы подобных условий в языке запросов, выясним, почему поведение системы может казаться нелогичным, и определим правильные способы решения задач хронологии.
Рассмотрим ситуацию, описанную в обсуждении. Разработчик видит запрос, в котором происходит левое соединение временной таблицы с самой собой по условию «меньше» для поля ссылки (Партии). Чтобы оперативно проверить результат работы такого кода, часто используется удобная консоль запросов, обеспечивающая высокую скорость отладки данных — для этого подойдёт универсальная консоль запросов и отладки кода 1С.
ВЫБРАТЬ
тз1.Номенклатура,
тз1.Партия,
тз1.Количество
ИЗ
втТЗ КАК тз1
ЛЕВОЕ СОЕДИНЕНИЕ втТЗ КАК тз2
ПО тз1.Номенклатура = тз2.Номенклатура
И тз1.Партия < тз2.Партия
Здесь поле Партия — это ссылка на документ. Возникает вопрос: корректно ли вообще сравнивать объекты ссылочного типа через операторы сравнения (больше >, меньше <), и какую логику при этом использует СУБД?
Чтобы понять логику работы запроса, нам нужно опуститься на уровень ниже — туда, как платформа транслирует этот код в SQL-запрос. В базе данных ссылка 1С (будь то СправочникСсылка или ДокументСсылка) хранится как уникальный идентификатор (UUID/GUID). Технически это поле типа BINARY(16) — последовательность из 16 байт (128 бит).
Когда вы пишете условие Ссылка1 < Ссылка2, платформа заставляет SQL-сервер сравнивать эти два 16-байтовых числа математически. То есть, сравниваются не даты документов, не их номера и не моменты времени, а именно их внутренние идентификаторы GUID. Для тех, кто стремится к совершенству в написании подобных конструкций, существуют специальные инструменты для анализа и автоматического редактирования модулей, помогающие канонизировать код по стандартам 1С.
Важно понимать: GUID — это просто очень большое число в шестнадцатеричном представлении. Одно число может быть больше или меньше другого, поэтому синтаксически запрос абсолютно корректен, и ошибок выполнения не возникнет.
Многие программисты замечают, что при таком сравнении документы часто выстраиваются в хронологическом порядке. Если создать документ сегодня, а второй завтра, то ссылка второго часто оказывается «больше» ссылки первого. Это вводит в заблуждение.
Причина кроется в алгоритме генерации GUID в платформе 1С. В отличие от стандарта случайных GUID (version 4), 1С использует алгоритм, основанный на времени (ближе к version 1), но с определенными модификациями для оптимизации работы индексов в MS SQL Server.
Рассмотрим факторы, влияющие на порядок:
Ссылка < Ссылка равносильно Дата < Дата.Таким образом, полагаться на сравнение ссылок для определения хронологии — это архитектурная ошибка. Это ненадежно и зависит от физической инфраструктуры сервера. Для выявления подобных и других неочевидных проблем в коде рекомендуется проводить регулярный анализ конфигураций на наличие ошибок.
В ходе анализа проблемы был затронут интересный нюанс: как ведет себя сравнение, если в поле Партия могут находиться документы разных видов (составной тип данных)? Например, ПоступлениеТоваровУслуг и АвансовыйОтчет.
В этом случае поле в базе данных на уровне SQL реализуется сложнее. Платформа оперирует не только ссылкой (UUID), но и Идентификатором типа (Type ID). Это внутренний номер таблицы метаданных в структуре базы.
Алгоритм сравнения для составного типа выглядит так:
Это объясняет наблюдение, почему документы одного вида могут быть всегда «больше» документов другого вида, даже если по дате они были созданы раньше. Дата здесь вообще не участвует в сравнении.
Иногда такие запросы пишут специалисты, долго работавшие с версией 1С 7.7. Давайте вспомним, как это было там.
В версии 7.7 существовало понятие ПозицияДокумента. Это была строка длиной 32 символа, которая формировалась специально для упорядочивания. Она включала в себя дату, время и ID документа. Сравнение строк ПозицияДокумента действительно давало точную хронологию с точностью до порядка внутри секунды.
В версии 8.х такой сущности в явном виде в БД нет. Вместо этого используется объект МоментВремени, который не является единым полем в таблице, а конструируется платформой динамически. Прямая пересадка логики из 7.7 (сравнение ссылок как позиций) на 8.х приводит к ошибкам, так как UUID в 8.х не содержит явной и строгой хронологической составляющей, пригодной для бизнес-логики.
Если ваша задача — получить остатки или обороты в хронологическом порядке (например, для списания партий по ФИФО), использовать Ссылка1 < Ссылка2 нельзя. Вам необходимо использовать комбинацию даты и ссылки, которая эмулирует понятие МоментВремени. Чтобы упростить работу разработчика и аналитика при написании таких запросов, стоит придерживаться проверенных методик.
В языке запросов стандартный паттерн для условия «Документ 1 раньше Документа 2» выглядит следующим образом:
ГДЕ
(Т1.Дата < Т2.Дата)
ИЛИ
(Т1.Дата = Т2.Дата И Т1.Ссылка < Т2.Ссылка)
Разберем это условие:
Т1.Дата < Т2.Дата — это основной критерий. Если один документ был проведен вчера, а другой сегодня, то первый явно раньше. Сравнение ссылок тут не требуется.(Т1.Дата = Т2.Дата И Т1.Ссылка < Т2.Ссылка) — это условие срабатывает, только если документы записаны в одну и ту же секунду. В пределах одной секунды 1С не гарантирует порядка по времени, поэтому для детерминированности сортировки мы вынуждены использовать ссылку как уникальный ключ. Внедряя подобные конструкции, полезно использовать готовые шаблоны для применения стандартов и методик разработки 1С, что значительно ускоряет процесс написания качественного кода.Этот подход гарантирует, что вы сначала обрабатываете документы по хронологии дат, а "спорные" ситуации внутри секунды решаете через сравнение GUID, что допустимо для технической сортировки.
Подводя итог анализу темы, сформулируем основные правила работы с операторами сравнения для ссылочных типов:
>, <) для бизнес-логики, завязанной на время (ФИФО, ЛИФО, хронология событий). Это ненадежно.Дата < Дата ИЛИ (Дата = Дата И Ссылка < Ссылка). Это аналог сравнения моментов времени в запросе.Используйте эти знания при проектировании запросов и анализе чужого кода, чтобы избегать трудноуловимых ошибок. Кстати, подобные вопросы часто встречаются на интервью, поэтому кандидатам будет полезно изучить методический материал для собеседования программиста, чтобы уверенно отвечать на вопросы о внутреннем устройстве платформы.