Мы часто сталкиваемся с ситуацией, когда для отображения актуальной информации в динамическом списке нам необходимо получить данные из регистра сведений, используя виртуальную таблицу СрезПоследних. Однако, если требуется получить срез для *каждого* элемента регистратора (например, для каждого документа), а не на фиксированную дату, стандартный подход с СрезПоследних становится сложнее. В таких случаях приходится строить более комплексные запросы с использованием временных таблиц. При этом могут возникнуть неочевидные проблемы с работой отборов в динамическом списке. Давайте разберем эту задачу по шагам и выясним, как ее успешно решить.
Рассмотрим подробнее проблему и ее решение, основываясь на опыте коллег и лучших практиках разработки на платформе 1С:Предприятие.
Одной из наиболее частых и при этом неочевидных причин некорректной работы отборов в динамическом списке при использовании сложных запросов является дублирование псевдонимов (алиасов) полей. Платформа 1С использует псевдонимы полей запроса для идентификации колонок, по которым можно устанавливать отборы. Если два поля из разных источников (например, из основной таблицы и из временной таблицы, или из двух разных соединений) имеют одинаковые псевдонимы, система может запутаться, к какому именно полю применять отбор.
Проанализируем ситуацию: в нашем запросе мы выбираем поле СтатусДокумента из временной таблицы вт_СтатусыИЭтапы. Если в основном источнике данных динамического списка (например, в таблице Документ.Документ1) уже есть поле с таким же именем или псевдонимом, или если мы используем поле из другого соединения с таким же псевдонимом, это может вызвать конфликт. Динамический список не сможет однозначно определить, какое из полей СтатусДокумента нужно фильтровать.
Как это исправить? Мы должны обеспечить уникальность псевдонимов для всех полей, по которым планируем устанавливать отборы, особенно если эти поля имеют схожие названия или приходят из разных источников данных. Давайте посмотрим на пример, который помог решить проблему:
Изначально в запросе поле выбиралось так:
ВЫБРАТЬ
...
вт_СтатусыИЭтапы.СтатусДокумента КАК СтатусДокумента,
...
Для устранения конфликта, мы изменили псевдоним поля СтатусДокумента на уникальный, например, р_СтатусДокумента:
ВЫБРАТЬ
...
вт_СтатусыИЭтапы.СтатусДокумента КАК р_СтатусДокумента,
...
Почему это работает? Присваивая уникальный псевдоним р_СтатусДокумента, мы явно указываем системе, что это конкретное поле из временной таблицы вт_СтатусыИЭтапы. Таким образом, при попытке установить отбор по полю р_СтатусДокумента в динамическом списке, платформа 1С однозначно понимает, какое поле нужно фильтровать, и отбор начинает работать корректно.
Всегда используйте явные и уникальные псевдонимы для полей в запросах динамических списков, особенно при соединении нескольких таблиц или использовании временных таблиц. Это является хорошей практикой и помогает избежать многих проблем с отборами и отображением данных.
Для того чтобы получить актуальные статусы для каждого документа, как правило, одного лишь вызова виртуальной таблицы СрезПоследних недостаточно, если мы хотим применить ее для каждого регистратора. Нам приходится строить пакетный запрос с использованием временных таблиц. Давайте разберем структуру такого запроса, предложенного в исходной теме, и выясним, как он работает.
Основная идея: Сначала мы определяем самый поздний период для каждого регистратора, а затем по этим периодам выбираем соответствующие записи из регистра сведений. Это позволяет эффективно обойти ограничения СрезПоследних, которая по умолчанию работает на одну фиксированную дату или без параметров для всего регистра.
Рассмотрим запрос пошагово:
На первом шаге мы создаем временную таблицу ДатаПоследнегоСтатуса. Ее задача — для каждого уникального регистратора определить самую позднюю дату записи в регистре сведений СтатусыДокументов.
ПОМЕСТИТЬ ДатаПоследнегоСтатуса
ИЗ
РегистрСведений.СтатусыДокументов.СрезПоследних(, Регистратор ССЫЛКА Документ.Документ1) КАК СтатусыДокументовСрезПоследних
СГРУППИРОВАТЬ ПО
СтатусыДокументовСрезПоследних.Регистратор
ВЫБРАТЬ
МАКСИМУМ(СтатусыДокументовСрезПоследних.Период) КАК Период,
СтатусыДокументовСрезПоследних.Регистратор КАК Регистратор
;
Здесь мы используем виртуальную таблицу РегистрСведений.СтатусыДокументов.СрезПоследних. Важно обратить внимание на параметр отбора Регистратор ССЫЛКА Документ.Документ1, который позволяет ограничить выборку только для документов определенного типа. Затем с помощью функции агрегации МАКСИМУМ(Период) и группировки по Регистратор, мы находим последнюю дату для каждого документа.
На втором шаге мы создаем временную таблицу вт_СтатусыИЭтапы, которая содержит последние статусы и этапы для каждого документа. Мы достигаем этого, соединяя полный регистр сведений СтатусыДокументов с нашей ранее созданной временной таблицей ДатаПоследнегоСтатуса.
ПОМЕСТИТЬ вт_СтатусыИЭтапы
ИЗ
РегистрСведений.СтатусыДокументов КАК СтатусыДокумента
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДатаПоследнегоСтатуса КАК ДатаПоследнегоСтатуса
ПО (СтатусыДокумента.Регистратор = ДатаПоследнегоСтатуса.Регистратор)
И (СтатусыДокумента.Период = ДатаПоследнегоСтатуса.Период)
ВЫБРАТЬ
СтатусыДокумента.СтатусДокумента КАК СтатусДокумента,
СтатусыДокумента.Этап КАК Этап,
СтатусыДокумента.Регистратор КАК Регистратор
;
Оператор ВНУТРЕННЕЕ СОЕДИНЕНИЕ позволяет нам сопоставить записи из регистра сведений с их последними периодами. Таким образом, в вт_СтатусыИЭтапы мы получаем только те записи, которые соответствуют последнему статусу для каждого регистратора.
На финальном шаге мы формируем итоговый запрос для динамического списка, соединяя основной документ (Документ.Документ1) с нашей временной таблицей вт_СтатусыИЭтапы и, при необходимости, с другими регистрами или таблицами (например, РегистрСведений.НаличиеФайлов).
ВЫБРАТЬ
Документ.Ссылка КАК Ссылка,
Документ.Дата КАК Дата,
Документ.Проведен КАК Проведен,
Документ.АвторДокумента КАК АвторДокумента,
Документ.Клиент КАК Клиент,
НаличиеФайлов.ЕстьФайлы КАК ЕстьФайлы,
вт_СтатусыИЭтапы.СтатусДокумента КАК р_СтатусДокумента, // Здесь мы применили уникальный псевдоним!
вт_СтатусыИЭтапы.Этап КАК Этап
ИЗ
Документ.Документ1 КАК Документ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НаличиеФайлов КАК НаличиеФайлов
ПО (Документ.Ссылка = НаличиеФайлов.ОбъектСФайлами)
ЛЕВОЕ СОЕДИНЕНИЕ вт_СтатусыИЭтапы КАК вт_СтатусыИЭтапы
ПО (Документ.Ссылка = вт_СтатусыИЭтапы.Регистратор)
Обратите внимание на ЛЕВОЕ СОЕДИНЕНИЕ с временной таблицей вт_СтатусыИЭтапы. Это позволяет нам получить статусы и этапы для всех документов, даже если для какого-то документа статуса еще нет (в этом случае поля р_СтатусДокумента и Этап будут иметь значение NULL).
Самое главное: здесь мы явно указываем уникальный псевдоним р_СтатусДокумента для поля СтатусДокумента из временной таблицы. Это критически важный момент для корректной работы отбора, как мы выяснили в первом решении.
Помимо основного решения, связанного с уникальностью псевдонимов, при работе с динамическими списками и сложными запросами с СрезПоследних следует учитывать ряд нюансов.
Производительность сложных запросов: Запросы, использующие несколько временных таблиц и соединения, могут быть ресурсоемкими. Если динамический список открывается долго или значительно нагружает сервер, рассмотрите возможности оптимизации:
Регистратор, Период), проиндексированы в регистре сведений.Особенности пакетных запросов в динамических списках: Динамические списки в 1С не поддерживают пакетные запросы напрямую в том смысле, что конечный источник данных для списка должен быть единым запросом. Однако, как мы видим, использование временных таблиц внутри одного пакетного запроса вполне допустимо и часто является необходимым приемом.
Фиксированные и динамические отборы: Помимо отборов, устанавливаемых пользователем, вы можете настраивать фиксированные отборы в конфигураторе или программно. Для программного управления отборами в форме динамического списка используйте объекты Элементы.ИмяСписка.Настройки.Отбор для настроек по умолчанию или Элементы.ИмяСписка.ФиксированныеНастройки.Отбор для отборов, недоступных пользователю. Помните, что при программной установке отбора по полю с уникальным псевдонимом (например, р_СтатусДокумента), именно этот псевдоним вы должны использовать в коде.
Проблемы с RLS (Row-Level Security): При использовании RLS могут возникнуть сложности с правами доступа, особенно при соединении основной таблицы со СрезомПоследних регистра сведений. Это может привести к ошибкам "Недостаточно прав". Всегда проверяйте, что у пользователя есть необходимые права на все таблицы, участвующие в запросе, включая временные.
"Объект не найден" при открытии регистратора: Если в качестве основной таблицы динамического списка вы напрямую укажете РегистрСведений.СрезПоследних (что не рекомендуется для такого сценария), при попытке открыть регистратор из списка может возникнуть ошибка "Объект не найден". Это происходит потому, что СрезПоследних не является таблицей объектов, и система не может автоматически определить, какой объект нужно открывать. В таких случаях требуется писать свой обработчик события ОбработкаВыбора или ПриАктивизацииСтроки для открытия регистратора.
Мы рассмотрели, как эффективно работать с отборами по полям регистра сведений в динамическом списке, даже если данные получаются из сложного запроса с использованием временных таблиц и срезов последних значений. Главный вывод: всегда уделяйте внимание уникальности псевдонимов полей в запросе, чтобы обеспечить корректную работу отборов. Это позволит создавать гибкие и функциональные динамические списки в ваших конфигурациях 1С.
← К списку