Ссылки в языке запросов 1С 8.3: от параметра до битых ссылок

· 9 мин

Содержание

Конкретную ссылку в запрос 1С вставляют двумя способами. Если ссылка известна в коде, её передают параметром: в тексте пишут &Контрагент, а в коде вызывают Запрос.УстановитьПараметр("Контрагент", СсылкаНаКонтрагента). Если нужна пустая ссылка, значение перечисления или предопределённый элемент, их пишут прямо в тексте через ЗНАЧЕНИЕ(...), например ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка).

Всё остальное в работе со ссылками в запросах вырастает из этих двух приёмов. Это разыменование через точку, отбор по типу документа в составном поле, поиск пустых и битых ссылок. Ниже всё это разобрано с примерами для платформы 8.3. Синтаксис языка запросов один для всех типовых конфигураций.

Что такое ссылка в запросе и чем она отличается от строки

Ссылка — это значение, которое указывает на конкретный объект базы: элемент справочника, документ, значение перечисления, счёт плана счетов. В таблице объекта у каждой записи есть поле Ссылка. Реквизиты других объектов хранят именно ссылку, а не наименование.

Отсюда главное правило: ссылку нельзя сравнивать со строкой. Условие ГДЕ Контрагент = "ООО Ромашка" не найдёт ничего. Нужно сравнивать либо со ссылкой, либо с реквизитом через точку: ГДЕ Контрагент.Наименование = "ООО Ромашка".

Какие ссылочные типы встречаются в запросах:

  • 📁 Справочник.<Имя> — элементы и группы справочников;
  • 📄 Документ.<Имя> — документы;
  • 🔢 Перечисление.<Имя> — значения перечислений;
  • 📊 ПланСчетов.<Имя>, ПланВидовХарактеристик.<Имя>, ПланВидовРасчета.<Имя>;
  • 🔁 БизнесПроцесс.<Имя>, Задача.<Имя>, ПланОбмена.<Имя>.

Через ссылку доступны реквизиты объекта. Запись Контрагент.ИНН платформа превращает в неявное левое соединение с таблицей контрагентов. Это удобно, но у этого есть цена, о ней — в разделе про скорость.

ЗначениеЧто этоКак проверить в запросе
Ссылка на объектУказывает на существующую записьПоле = &Ссылка
Пустая ссылкаСсылка нужного типа, но ни на что не указываетПоле = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
NULLЗначения нет вообще (обычно после левого соединения)Поле ЕСТЬ NULL
НЕОПРЕДЕЛЕНОПустое значение составного типаПоле = НЕОПРЕДЕЛЕНО

Как передать ссылку в запрос: параметр, ЗНАЧЕНИЕ(), список

Ссылка параметром

Самый частый случай. Ссылку получили в коде — из формы, из реквизита документа, из другого запроса — и передали в текст запроса:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Реализация.Ссылка КАК Документ,
|	Реализация.Дата КАК Дата,
|	Реализация.СуммаДокумента КАК Сумма
|ИЗ
|	Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
|	Реализация.Контрагент = &Контрагент
|	И Реализация.Проведен";

Запрос.УстановитьПараметр("Контрагент", Объект.Контрагент);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	Сообщить(Строка(Выборка.Документ) + ": " + Формат(Выборка.Сумма, "ЧДЦ=2"));
КонецЦикла;

Имя параметра в тексте и в УстановитьПараметр должно совпадать до буквы. Если параметр не установлен, запрос упадёт с ошибкой при выполнении.

Несколько ссылок сразу

Для отбора по списку ссылок используют В (&Список). В параметр можно передать массив, список значений или фиксированный массив:

Склады = Новый Массив;
Склады.Добавить(СкладОсновной);
Склады.Добавить(СкладРозница);

Запрос.Текст = "ВЫБРАТЬ Ост.Номенклатура, Ост.КоличествоОстаток
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад В (&Склады)) КАК Ост";
Запрос.УстановитьПараметр("Склады", Склады);

Имя регистра здесь условное: в вашей конфигурации оно может быть другим. Посмотреть точное имя можно в дереве метаданных в Конфигураторе.

Предопределённые элементы и перечисления через ЗНАЧЕНИЕ()

Если ссылка заранее известна в метаданных, параметр не нужен. Пишите её прямо в тексте:

ГДЕ
	Документ.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийРеализацияТоваров.ПродажаКомиссия)
	И Документ.ВалютаДокумента <> ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
	И Проводки.СчетДт = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.РасчетыСПокупателями)

ЗНАЧЕНИЕ() работает только с тремя вещами:

  1. Пустыми ссылками — ЗНАЧЕНИЕ(Документ.<Имя>.ПустаяСсылка).
  2. Значениями перечислений — ЗНАЧЕНИЕ(Перечисление.<Имя>.<Значение>).
  3. Предопределёнными элементами справочников, планов счетов и планов видов характеристик.

Обычный элемент справочника, созданный пользователем, через ЗНАЧЕНИЕ() получить нельзя. Только параметром. Имя предопределённого элемента смотрите в Конфигураторе: откройте справочник в дереве метаданных и нажмите кнопку «Предопределённые».

Найти ссылку по наименованию, коду или имени

Когда в коде есть только строка, ссылку достают тем же запросом:

ВЫБРАТЬ ПЕРВЫЕ 1
	Контрагенты.Ссылка КАК Ссылка
ИЗ
	Справочник.Контрагенты КАК Контрагенты
ГДЕ
	Контрагенты.ИНН = &ИНН
	И НЕ Контрагенты.ПометкаУдаления

ВЫБРАТЬ ПЕРВЫЕ 1 страхует от дублей: если в базе два контрагента с одним ИНН, вы получите один, а не таблицу. Для предопределённых элементов в 8.3 есть поле ИмяПредопределенныхДанных. По нему удобно искать элемент, когда имя хранится в настройке строкой.

Как получить реквизиты по ссылке и сделать выборку

Выборка по ссылке почти всегда нужна ради реквизитов. Есть три пути.

Путь 1. Разыменование через точку. Коротко и читаемо:

ВЫБРАТЬ
	Реализация.Ссылка,
	Реализация.Контрагент.ИНН КАК ИНН,
	Реализация.Контрагент.ОсновнойДоговор.Наименование КАК Договор
ИЗ
	Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
	Реализация.Ссылка = &Документ

Каждая точка — это ещё одно соединение. Две точки подряд — два соединения.

Путь 2. Явное левое соединение. Пишется длиннее, зато вы управляете условиями:

ВЫБРАТЬ
	Реализация.Ссылка,
	Контрагенты.ИНН КАК ИНН
ИЗ
	Документ.РеализацияТоваровУслуг КАК Реализация
		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
		ПО Реализация.Контрагент = Контрагенты.Ссылка
ГДЕ
	Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Если у документа контрагент пустой, строка всё равно попадёт в результат, а ИНН будет NULL.

Путь 3. Табличная часть через поле Ссылка. В табличной части поле Ссылка указывает на документ-владелец. Так можно сразу отобрать строки товаров нужного документа:

ВЫБРАТЬ
	Товары.НомерСтроки,
	Товары.Номенклатура,
	Товары.Количество
ИЗ
	Документ.РеализацияТоваровУслуг.Товары КАК Товары
ГДЕ
	Товары.Ссылка = &Документ
УПОРЯДОЧИТЬ ПО
	Товары.НомерСтроки

💡 Чтобы вывести ссылку текстом, используйте ПРЕДСТАВЛЕНИЕ(Поле) или ПРЕДСТАВЛЕНИЕССЫЛКИ(Поле). Само поле Ссылка оставляйте в выборке рядом: по нему пользователь сможет открыть объект из отчёта.

Составные типы: ССЫЛКА, ВЫРАЗИТЬ и ТИПЗНАЧЕНИЯ

Составной тип — это поле, которое может хранить ссылки разных типов. Классический пример — Регистратор в регистрах: там лежит любой документ, который делает движения. Ещё примеры — Субконто1 в проводках или реквизит «Основание» в документах.

Для таких полей в языке запросов есть три инструмента.

КонструкцияЧто делаетПример
ССЫЛКАПроверяет, что значение — ссылка указанного типаРегистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
ВЫРАЗИТЬПриводит поле к одному типу, чтобы взять реквизитВЫРАЗИТЬ(Регистратор КАК Документ.ПоступлениеТоваровУслуг).Номер
ТИПЗНАЧЕНИЯ + ТИПВозвращает тип значения для сравнения или группировкиТИПЗНАЧЕНИЯ(Субконто1) = ТИП(Справочник.Контрагенты)

Пример: движения по регистру только от документов поступления, с номером входящего документа.

ВЫБРАТЬ
	Движения.Регистратор КАК Документ,
	ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Дата КАК ДатаДокумента,
	Движения.Количество
ИЗ
	РегистрНакопления.ТоварыНаСкладах КАК Движения
ГДЕ
	Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг

Почему не написать просто Движения.Регистратор.Дата? Платформа не знает, какой именно документ там лежит. Поэтому она соединит регистр со всеми таблицами документов, которые могут быть регистраторами. В регистре с двадцатью видами регистраторов это двадцать соединений ради одного поля.

Через ТИПЗНАЧЕНИЯ удобно посчитать, сколько движений сделал каждый вид документов:

ВЫБРАТЬ
	ТИПЗНАЧЕНИЯ(Движения.Регистратор) КАК ВидДокумента,
	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Движения.Регистратор) КАК Документов
ИЗ
	РегистрНакопления.ТоварыНаСкладах КАК Движения
СГРУППИРОВАТЬ ПО
	ТИПЗНАЧЕНИЯ(Движения.Регистратор)

Если ВЫРАЗИТЬ применить к значению другого типа, результат будет NULL, без ошибки. Поэтому ВЫРАЗИТЬ в выборке обычно ставят вместе с условием ССЫЛКА в ГДЕ. Иначе в отчёте появятся пустые строки.

Как ускорить запросы со ссылками

Медленные запросы со ссылками почти всегда упираются в лишние соединения. Вот что даёт реальный выигрыш.

  1. Приводите составные поля через ВЫРАЗИТЬ до точки. ВЫРАЗИТЬ(Регистратор КАК Документ.X).Реквизит вместо Регистратор.Реквизит. Это главный приём из всех.
  2. Не разыменовывайте ссылки в параметрах виртуальных таблиц без нужды. Условие вроде Номенклатура.Родитель = &Группа внутри .Остатки(...) добавляет соединение в подзапрос регистра. Чаще быстрее отобрать номенклатуру во временную таблицу, а потом соединиться с ней.
  3. Кладите набор ссылок во временную таблицу с индексом. Если отбор идёт по тысячам ссылок, В (&Массив) работает хуже, чем соединение с таблицей:
ВЫБРАТЬ
	Номенклатура.Ссылка КАК Номенклатура
ПОМЕСТИТЬ ВТ_Товары
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.Ссылка В ИЕРАРХИИ (&Группа)
ИНДЕКСИРОВАТЬ ПО
	Номенклатура
;
ВЫБРАТЬ
	Ост.Номенклатура,
	Ост.КоличествоОстаток
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(
		,
		Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Товары КАК ВТ)) КАК Ост
  1. Не читайте реквизиты по ссылке в цикле в коде. Строка Выборка.Документ.Контрагент.ИНН внутри цикла на каждой итерации обращается к базе. На тысяче строк это тысяча лишних чтений. Берите ИНН полем того же запроса.
  2. Не выбирайте ПРЕДСТАВЛЕНИЕ там, где оно не выводится. Для составных полей получение представления тоже тянет соединения со всеми таблицами типов.

Проверить, что изменилось, можно замером производительности в режиме отладки: время выполнения запроса видно по строке Запрос.Выполнить().

Пустые, NULL и битые ссылки

Пустая ссылка и NULL

Это разные вещи, и путают их постоянно.

  • 🔹 Пустая ссылка хранится в поле, когда реквизит не заполнили. У неё есть тип. Проверка — = ЗНАЧЕНИЕ(Справочник.<Имя>.ПустаяСсылка).
  • 🔹 NULL появляется, когда записи нет: левое соединение не нашло пару, ВЫРАЗИТЬ не подошёл по типу. Проверка — ЕСТЬ NULL.

Чтобы отобрать «не заполнено» с учётом обоих случаев, удобно свернуть их в одно условие:

ГДЕ
	ЕСТЬNULL(Контрагенты.Ссылка, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка))
		= ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

Для составного типа пустое значение — НЕОПРЕДЕЛЕНО. В условиях по такому полю проверяйте и его.

Битые ссылки

Битая ссылка указывает на объект, которого в базе уже нет. Его удалили напрямую, без контроля ссылочной целостности, или он потерялся при неудачном обмене. В форме такое значение показывается как <Объект не найден> с идентификатором в скобках.

Найти битые ссылки запросом можно через левое соединение: в поле ссылка не пустая, а парной записи в таблице объекта нет.

ВЫБРАТЬ
	Реализация.Ссылка КАК Документ,
	Реализация.Контрагент КАК БитаяСсылка
ИЗ
	Документ.РеализацияТоваровУслуг КАК Реализация
		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
		ПО Реализация.Контрагент = Контрагенты.Ссылка
ГДЕ
	Реализация.Контрагент <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
	И Контрагенты.Ссылка ЕСТЬ NULL

Такой запрос показывает, в каких документах проблема. Исправлять дальше можно вручную: открыть документ и выбрать правильного контрагента.

Если битых ссылок много и по разным объектам, есть штатный инструмент. В Конфигураторе: Администрирование → Тестирование и исправление, флажок «Проверка ссылочной целостности информационной базы». Для найденных битых ссылок можно выбрать действие: создавать объекты-заглушки, очищать ссылки или не изменять.

Перед тестированием и исправлением сделайте резервную копию базы (выгрузку .dt или копию средствами СУБД). Режим «Очищать ссылки» необратимо стирает значения в реквизитах. Режим «Создавать объекты» плодит пустые элементы с пометкой «Объект не найден», их потом придётся разбирать. Для проверки нужен монопольный доступ: заранее предупредите пользователей, их сеансы придётся завершить.

Безопасная последовательность: сначала прогнать проверку с вариантом «Не изменять» и прочитать протокол. Решение о действии принимать уже по нему.

Ошибки, которые встречаются чаще всего

Диагностика: выберите симптом

Частые вопросы

Можно ли вставить ссылку в текст запроса строкой с идентификатором?
Нет. Язык запросов не принимает GUID в тексте. Получите ссылку в коде через ПолучитьСсылку(Новый УникальныйИдентификатор(...)) у менеджера справочника или документа и передайте её параметром.
Как в консоли запросов задать параметр-ссылку?
В консоли откройте список параметров, выберите тип значения нужного справочника или документа и укажите элемент из списка. Для пустой ссылки удобнее заменить параметр на ЗНАЧЕНИЕ(…ПустаяСсылка) прямо в тексте.
Сравнение Поле = &Ссылка учитывает пометку удаления?
Нет. Помеченные на удаление объекты тоже попадут в результат. Если они не нужны, добавьте условие НЕ Поле.ПометкаУдаления или проверку Проведен для документов.
Чем ПРЕДСТАВЛЕНИЕССЫЛКИ отличается от ПРЕДСТАВЛЕНИЕ?
ПРЕДСТАВЛЕНИЕССЫЛКИ рассчитана на ссылочные значения и возвращает их текстовое представление. ПРЕДСТАВЛЕНИЕ универсальна: подходит для любых типов, включая числа, даты и булево.
Нужно ли выбирать поле Ссылка, если в отчёте выводятся только реквизиты?
Да, если пользователь должен открывать объект из отчёта: расшифровка в отчётах на СКД работает через ссылку. Если отчёт только печатается, без него можно обойтись.