Разработка и Конфигурация · 11 мин
Как в запросе 1С получить битую ссылку
Как найти битую ссылку в запросе 1С: проверка через NULL, соединение с справочником, типы битых ссылок, примеры кода, типичные ошибки и способы исправления.
Битая ссылка в 1С — это значение ссылочного типа, которое указывает на объект, уже удалённый из информационной базы. Физически в поле таблицы остаётся идентификатор (GUID), но записи с таким идентификатором в таблице-владельце больше нет. При обращении к такому объекту платформа возвращает представление вида «<Объект не найден> (…): …», а попытка получить его реквизиты приводит к неочевидным ошибкам в отчётах и обработках.
Чаще всего битые ссылки появляются после прямого удаления объектов без контроля ссылочной целостности, после обменов данными, когда объект выгружен, а его владелец — нет, а также после нештатного восстановления базы из копии. Проблема особенно заметна в запросах: левое соединение с таблицей справочника или документа по такой ссылке возвращает NULL, и строки либо теряются, либо искажают итоги.
Задача «получить битую ссылку в запросе» обычно ставится двояко: либо нужно найти все записи, где ссылка битая, чтобы их исправить, либо нужно корректно обработать такие ссылки прямо в запросе, чтобы отчёт не падал и не врал. Ниже разобраны оба сценария с готовыми конструкциями языка запросов.
Что такое битая ссылка и как она выглядит в запросе
В языке запросов 1С битая ссылка ведёт себя неоднозначно. Само поле ссылки не равно NULL — в нём лежит вполне конкретный идентификатор. Но любое обращение через точку к реквизитам несуществующего объекта (разыменование) возвращает NULL, а левое соединение с таблицей объекта не находит пару и тоже даёт NULL в присоединённых полях.
Именно это свойство и используется для обнаружения. Если поле Товары.Номенклатура заполнено, но Справочник.Номенклатура.Ссылка при соединении по этому полю равно NULL — объект номенклатуры удалён, а ссылка осталась. Это и есть надёжный признак битой ссылки в запросе.
Важно отличать битую ссылку от пустой. Пустая ссылка — это допустимое значение «ничего не выбрано», оно хранится в базе и корректно сравнивается с ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка). Битая ссылка — это признак повреждения данных, и обрабатывать её нужно иначе.
Как найти битые ссылки через левое соединение
Базовый приём — левое соединение таблицы, где хранится ссылка, с таблицей объекта и проверка результата соединения на NULL. Пример для табличной части документа:
ВЫБРАТЬ
РеализацияТовары.Ссылка КАК Документ,
РеализацияТовары.Номенклатура КАК БитаяСсылка
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
ПО РеализацияТовары.Номенклатура = Номенклатура.Ссылка
ГДЕ
НЕ РеализацияТовары.Номенклатура ЕСТЬ NULL
И РеализацияТовары.Номенклатура <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
И Номенклатура.Ссылка ЕСТЬ NULL
Три условия в секции ГДЕ обязательны вместе. Первое отсекает NULL в самом поле (возможен в регистрах и составных типах), второе исключает штатные пустые ссылки, третье фиксирует отсутствие объекта в базе. Только комбинация всех трёх даёт именно битые ссылки, а не пустые значения.
Если поле имеет составной тип (например, «Субконто» в проводках или «Контрагент» с типами «Справочник.Контрагенты» и «Справочник.Организации»), соединение нужно делать с каждой таблицей из состава типа и проверять, что не нашлось ни одной пары. Для этого удобно использовать ВЫРАЗИТЬ(Поле КАК Справочник.НужныйТип) перед соединением — приведение типа отсечёт значения чужих типов, и логика проверки останется прозрачной.
Как получить битую ссылку средствами встроенного языка
Если запрос уже вернул выборку и нужно проверить каждую ссылку программно, используется метод ПолучитьОбъект(): для битой ссылки он возвращает Неопределено. Типовой фрагмент проверки:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Номенклатура.ПолучитьОбъект() = Неопределено Тогда
// Ссылка битая: объект не существует
КонецЕсли;
КонецЦикла;
Этот способ точен, но медленен на больших выборках — каждый вызов обращается к базе. Поэтому массовый поиск битых ссылок всегда делают запросом с соединением, а проверку через ПолучитьОбъект() применяют только для точечной диагностики отдельных значений.
Для комплексной проверки всей базы в типовых конфигурациях есть штатный механизм: тестирование и исправление информационной базы с включённой проверкой ссылочной целостности. Он находит битые ссылки по всем таблицам и может автоматически очищать их или создавать объекты-заглушки. Запросы нужны там, где требуется выборочный анализ или обработка внутри прикладной логики.
Способы обнаружения битых ссылок
Подходит для массового поиска по конкретным полям. Быстро, но требует перечислять проверяемые таблицы вручную.
Точная точечная проверка в коде. Медленно на больших объёмах, не подходит для пакетной диагностики.
Проверяет всю базу целиком штатными средствами. Требует монопольного доступа и работает долго на больших базах.
Как исправить найденные битые ссылки
Найти битую ссылку — половина задачи. Дальше есть три варианта действий. Первый — очистить ссылку, записав в поле пустое значение соответствующего типа. Это уместно, когда ссылка не несёт учётного смысла, например в служебных регистрах сведений.
Второй вариант — заменить битую ссылку на специально созданный объект-заглушку, например элемент справочника «Неизвестный контрагент». Так делают, когда поле обязательно к заполнению и участвует в отчётности: итоги сохраняются, а проблемные строки видны отдельной группой.
Третий вариант — восстановить объект из резервной копии или из базы-источника обмена, если известен GUID. У битой ссылки идентификатор сохранился, и объект можно создать заново с тем же GUID через ПолучитьСсылку(Новый УникальныйИдентификатор(...)) и запись. Это самый трудоёмкий, но единственный способ вернуть реальные данные.
Типичные ошибки при работе с битыми ссылками в запросах
Самая частая ошибка — попытка найти битые ссылки условием Поле ЕСТЬ NULL без соединения. Такой запрос вернёт только строки, где поле физически пусто в составном типе, и не покажет ни одной битой ссылки, хотя визуально кажется, что проверка правильная.
Вторая ошибка — забыть исключить пустые ссылки. Условие «соединённая ссылка ЕСТЬ NULL» срабатывает и для пустых ссылок, потому что пустая ссылка не соединяется с реальными строками таблицы. Без фильтра на ПустаяСсылка в результат попадают тысячи штатных незаполненных полей, и реальные битые ссылки тонут в шуме.
Третья группа ошибок связана с составными типами: соединение только с одной таблицей из состава типа помечает «битыми» все значения других допустимых типов. И наконец, опасно сразу удалять найденные записи запросом — сначала нужно понять, почему ссылка побилась, иначе проблема воспроизведётся после очередного обмена.
Как проверить результат
ПолучитьОбъект() возвращает Неопределено, в интерфейсе «Объект не найден»
Объект открывается и существует — значит, запрос написан с ошибкой
Небольшое число записей, соответствующее истории удалений и обменов
Тысячи строк — вероятно, в выборку попали пустые ссылки или чужие типы
Нет пустых строк и меток «Объект не найден», итоги сходятся
Итоги изменились без объяснения — проверьте, что очищали именно битые ссылки
Частые вопросы
Можно ли получить битую ссылку без соединения с таблицей объекта?
Через разыменование реквизита с проверкой на NULL — частично, но этот способ ненадёжен: незаполненный реквизит реального объекта тоже даст NULL. Полноценная и однозначная проверка возможна только через соединение с таблицей-владельцем или программно через ПолучитьОбъект().
Чем битая ссылка отличается от пустой ссылки в запросе?
Пустая ссылка — штатное значение «ничего не выбрано», она сравнивается с ЗНАЧЕНИЕ(...ПустаяСсылка) и не является ошибкой. Битая ссылка указывает на удалённый объект: она не равна пустой, но не соединяется ни с одной строкой таблицы объекта и требует исправления данных.
Почему запрос с условием «Ссылка ЕСТЬ NULL» не находит битые ссылки?
Потому что в поле ссылки хранится идентификатор удалённого объекта, а не NULL. NULL появляется только в присоединённых полях при соединении или при разыменовании реквизитов несуществующего объекта, поэтому проверять на NULL нужно результат соединения, а не саму ссылку.
Откуда берутся битые ссылки, если удаление проходит с контролем целостности?
Типичные источники — прямое удаление объектов внешними обработками без контроля ссылок, обмены данными, когда объект выгружен, а связанный объект нет или пришёл позже, а также восстановление базы из копии, снятой в момент незавершённой транзакции.
Как массово проверить всю базу, а не отдельные поля?
Используйте штатное тестирование и исправление информационной базы с проверкой ссылочной целостности — оно проходит по всем таблицам автоматически. Запросы с соединениями применяйте для точечной диагностики конкретных полей или когда проверка нужна внутри прикладной обработки.
Можно ли восстановить объект, на который указывает битая ссылка?
Да, если известен GUID объекта и есть источник данных — резервная копия или база обмена. Объект создаётся заново с тем же уникальным идентификатором через ПолучитьСсылку() и заполняется данными из источника. Если источника нет, остаётся очистка ссылки или замена на объект-заглушку.
Что важно запомнить
Битую ссылку в запросе 1С находят левым соединением с таблицей объекта и тремя условиями: поле не NULL, поле не пустая ссылка, соединённая ссылка ЕСТЬ NULL. Само поле ссылки NULL не содержит. Массовую проверку всей базы делайте тестированием и исправлением, а любые исправления — только после резервного копирования.