При разработке и доработке печатных форм, отчетов или алгоритмов проведения документов разработчики нередко сталкиваются с ошибкой выполнения запроса вида: {(Строка, Колонка)}: Неоднозначное поле "ИмяТаблицы.Ссылка". Разберем подробно, почему платформа 1С выдает такое сообщение и как быстро и правильно устранить эту проблему.
Проанализируем типовую ситуацию на практическом примере. При попытке сформировать печатную форму документа СписаниеТоваров возникает исключение:
{Документ.СписаниеТоваров.МодульОбъекта(928)}: Ошибка при вызове метода контекста (Выполнить)
Док = Запрос.Выполнить().Выбрать();
по причине:
{(17, 2)}: Неоднозначное поле "СписаниеТоваров.Ссылка"
<<?>>СписаниеТоваров.Ссылка = &ТекДокумент
Посмотрим на исходный текст запроса, вызвавший данное исключение:
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТекДокумент", ЭтотОбъект.Ссылка);
Запрос.УстановитьПараметр("Дата", Дата);
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| СписаниеТоваров.Номер,
| СписаниеТоваров.Дата КАК ДатаДокумента,
| СписаниеТоваров.Организация,
| СписаниеТоваров.СтруктурноеПодразделение,
| СписаниеТоваров.Склад.Представление КАК СкладПредставление,
| СписаниеТоваров.ИнвентаризационнаяКомиссия.(
| ФизЛицо КАК ФизЛицо,
| Председатель КАК Председатель
| ),
| ОтветственныеЛицаСрезПоследних.ФизическоеЛицо КАК ОтветственноеЛицо
|ИЗ
| Документ.СписаниеТоваров КАК СписаниеТоваров
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ОтветственныеЛица.СрезПоследних(&Дата, ) КАК ОтветственныеЛицаСрезПоследних
| ПО СписаниеТоваров.Склад = ОтветственныеЛицаСрезПоследних.СтруктурнаяЕдиница
|ГДЕ
| СписаниеТоваров.Ссылка = &ТекДокумент";
Док = Запрос.Выполнить().Выбрать();
Платформа 1С выдает ошибку о неоднозначности поля тогда, когда синтаксический анализатор не может однозначно определить, к какому именно источнику данных или уровню вложенности относится указанное поле. Выделим основные факторы, приводящие к такому поведению:
СписаниеТоваров, и при этом в конфигурации существует одноименный реквизит, табличная часть или соединяемая таблица с похожей структурой, платформа не может определить, обращается разработчик к таблице-источнику или к реквизиту.СписаниеТоваров.ИнвентаризационнаяКомиссия.(...) неявно создает вложенную выборку. Строки табличной части также содержат скрытое системное поле Ссылка (ссылку на документ-владелец). При совпадении имени псевдонима основной таблицы с именем метаданных парсер путает уровень шапки документа и уровень строк вложенной таблицы.ВЫБРАТЬ РАЗРЕШЕННЫЕ платформа динамически дописывает шаблоны ограничений прав доступа в секцию ГДЕ. Если псевдоним таблицы совпадает с именем метаданных, внедряемый код условий RLS конфликтует с текстом запроса, что приводит к неоднозначности. Именно поэтому в базе с полными правами запрос может работать корректно, а у пользователя с ограниченными правами падать с ошибкой.Рассмотрим самое простое и быстрое исправление — переименование псевдонима (алиаса) таблицы в секции ИЗ на уникальное имя, которое не дублирует имя метаданных конфигурации.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТекДокумент", ЭтотОбъект.Ссылка);
Запрос.УстановитьПараметр("Дата", Дата);
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ДокСписание.Номер,
| ДокСписание.Дата КАК ДатаДокумента,
| ДокСписание.Организация,
| ДокСписание.СтруктурноеПодразделение,
| ДокСписание.Склад.Представление КАК СкладПредставление,
| ДокСписание.ИнвентаризационнаяКомиссия.(
| ФизЛицо КАК ФизЛицо,
| Председатель КАК Председатель
| ),
| ОтветственныеЛицаСрезПоследних.ФизическоеЛицо КАК ОтветственноеЛицо
|ИЗ
| Документ.СписаниеТоваров КАК ДокСписание
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ОтветственныеЛица.СрезПоследних(&Дата, ) КАК ОтветственныеЛицаСрезПоследних
| ПО ДокСписание.Склад = ОтветственныеЛицаСрезПоследних.СтруктурнаяЕдиница
|ГДЕ
| ДокСписание.Ссылка = &ТекДокумент";
ВыборкаДокумент = Запрос.Выполнить().Выбрать();
Заменив псевдоним СписаниеТоваров на ДокСписание (или ШапкаДокумента), мы полностью исключаем конфликт имен для транслятора запросов 1С.
Разберем более надежный и профессиональный подход. Выборка табличных частей через точку в основном запросе (вложенные таблицы) считается устаревшей практикой: она создает избыточную нагрузку на СУБД и часто провоцирует ошибки неоднозначности полей при наложении условий RLS. Стандарты разработки 1С рекомендуют использовать пакетные запросы с методом ВыполнитьПакет().
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТекДокумент", ЭтотОбъект.Ссылка);
Запрос.УстановитьПараметр("Дата", Дата);
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ДокШапка.Номер КАК Номер,
| ДокШапка.Дата КАК ДатаДокумента,
| ДокШапка.Организация КАК Организация,
| ДокШапка.СтруктурноеПодразделение КАК СтруктурноеПодразделение,
| ДокШапка.Склад.Представление КАК СкладПредставление,
| ОтветственныеЛицаСрезПоследних.ФизическоеЛицо КАК ОтветственноеЛицо
|ИЗ
| Документ.СписаниеТоваров КАК ДокШапка
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ОтветственныеЛица.СрезПоследних(&Дата, ) КАК ОтветственныеЛицаСрезПоследних
| ПО ДокШапка.Склад = ОтветственныеЛицаСрезПоследних.СтруктурнаяЕдиница
|ГДЕ
| ДокШапка.Ссылка = &ТекДокумент
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ТабКомиссия.ФизЛицо КАК ФизЛицо,
| ТабКомиссия.Председатель КАК Председатель
|ИЗ
| Документ.СписаниеТоваров.ИнвентаризационнаяКомиссия КАК ТабКомиссия
|ГДЕ
| ТабКомиссия.Ссылка = &ТекДокумент";
МассивРезультатов = Запрос.ВыполнитьПакет();
ВыборкаШапка = МассивРезультатов[0].Выбрать();
ВыборкаКомиссия = МассивРезультатов[1].Выбрать();
Использование пакетного запроса гарантирует отсутствие конфликтов между шапкой и строками табличной части, позволяет прозрачно управлять условиями фильтрации и повышает общую производительность системы.