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