Как в запросе 1С реализовать отбор по нескольким парам параметров одновременно?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке сложных отчетов или обработок в системе 1С:Предприятие часто возникает задача отобрать данные по списку пар (или более широких наборов) значений. Например, нам нужно выбрать документы, в табличных частях которых встречаются определенные комбинации «Номенклатура + Серия» или «Номенклатура + Характеристика». Если таких пар всего две-три, можно обойтись громоздким условием ГДЕ (Условие1 И Условие2) ИЛИ (Условие3 И Условие4). Однако, если количество условий (N) велико или они передаются динамически из таблицы значений, такой подход становится неэффективным и неудобным в сопровождении.

В этой статье мы подробно разберем, как реализовать изящный отбор по группе полей, используя механизмы временных таблиц и работу с кортежами в языке запросов 1С.

Использование конструкции выбора по кортежам полей

Самый эффективный и читаемый способ решения данной задачи — использование специального синтаксиса сравнения нескольких полей одновременно с помощью оператора В. Рассмотрим ситуацию, когда у нас есть Таблица Значений (ТЗ), содержащая колонки Номенклатура и СерияНоменклатуры, и нам нужно выбрать данные, соответствующие только этим парам.

Проанализируем алгоритм действий:

  1. Передаем таблицу значений с парами параметров в запрос.
  2. Помещаем эти данные во временную таблицу.
  3. В основном запросе накладываем условие на кортеж полей основной таблицы, сравнивая его с данными из временной таблицы.

Посмотрим на пример реализации кода на встроенном языке:


// Допустим, ТаблицаПараметров уже заполнена нужными парами Номенклатура и Серия
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

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

Запрос.УстановитьПараметр("ТаблицаПараметров", ТаблицаПараметров);
Результат = Запрос.Выполнить();

В данном примере мы используем конструкцию (ТЧ.Номенклатура, ТЧ.СерияНоменклатуры) В (...). Это позволяет системе за один проход сопоставить сразу оба поля с эталонными значениями. Это гораздо быстрее и компактнее, чем генерация динамического текста запроса с множеством условий ИЛИ.

Альтернативный подход: Внутреннее соединение (INNER JOIN)

Рассмотрим еще один способ решения задачи — использование внутреннего соединения основной таблицы с временной таблицей параметров. Этот метод часто кажется программистам более наглядным.

Выясним, как это выглядит в коде запроса:


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

Несмотря на внешнюю схожесть, между этими двумя подходами (В и СОЕДИНЕНИЕ) есть критическое различие, которое необходимо учитывать:

  1. Проблема дублей: Если во временной таблице ВТ_КритерииОтбора одна и та же пара (Номенклатура + Серия) встретится дважды, то Внутреннее соединение «размножит» строки основной таблицы в результате запроса. Вам придется использовать ВЫБРАТЬ РАЗЛИЧНЫЕ, что создает дополнительную нагрузку на СУБД.
  2. Semi-join: Оператор В работает по принципу «полусоединения» (Semi-join). Он просто проверяет наличие совпадения. Даже если в таблице-источнике параметров есть дубли, строка основной таблицы попадет в результат только один раз. Это более безопасный метод с точки зрения логики получения данных.

Особенности работы с виртуальными таблицами

Проанализируем ситуацию, когда отбор нужно наложить на виртуальную таблицу, например, на РегистрНакопления.ТоварыНаСкладах.Остатки. В этом случае использование кортежей дает огромное преимущество в производительности.

Если мы выполним соединение с виртуальной таблицей после ее получения, система сначала рассчитает остатки по всем товарам и сериям, а затем отсечет лишние. Чтобы ускорить запрос, условие нужно передать непосредственно в параметры виртуальной таблицы.

Разберем пример:


ВЫБРАТЬ
	ТоварыНаСкладахОстатки.Номенклатура,
	ТоварыНаСкладахОстатки.СерияНоменклатуры,
	ТоварыНаСкладахОстатки.В НаличииОстаток
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(
			,
			(Номенклатура, СерияНоменклатуры) В
				(ВЫБРАТЬ
					ВТ.Номенклатура,
					ВТ.Серия
				ИЗ
					ВТ_КритерииОтбора КАК ВТ)) КАК ТоварыНаСкладахОстатки

Важно: При таком подходе СУБД (будь то MS SQL Server или PostgreSQL) сможет максимально эффективно использовать индексы, и выборка данных произойдет только по нужным парам значений на этапе чтения из физических таблиц базы данных.

Технические нюансы и производительность

При использовании отбора по кортежам следует помнить о нескольких важных моментах, которые влияют на стабильность и скорость работы системы:

1. Наличие индексов. Для того чтобы конструкция (Поле1, Поле2) В (...) работала быстро, в базе данных должен существовать подходящий составной индекс. Порядок полей в индексе должен в идеале совпадать с порядком полей в вашем запросе. Если индексы созданы только по отдельным полям, СУБД может выбрать менее оптимальный план выполнения.

2. Обработка значений NULL. Будьте внимательны при сравнении полей, которые могут содержать NULL. В SQL сравнение NULL = NULL не дает истины (результат будет "Unknown"). Если в вашей временной таблице или в данных ТЧ есть NULL в одном из полей кортежа, такая строка может не попасть в выборку. Рекомендуется использовать функцию ЕСТЬNULL(Поле, ЗначениеЗаглушка) для обеспечения предсказуемого результата.

3. Ограничения СУБД. Хотя синтаксис 1С универсален, под капотом он транслируется в разные SQL-команды. Современные версии PostgreSQL поддерживают кортежи напрямую. MS SQL Server старых версий может преобразовывать их в конструкцию EXISTS. В подавляющем большинстве случаев это работает быстро, но при использовании очень больших списков параметров (десятки тысяч строк во временной таблице) стоит предварительно протестировать производительность на реальных данных.

4. Передача параметров напрямую. Стоит отметить, что 1С не позволяет передать список пар значений напрямую через УстановитьПараметр(), как это делается с обычным массивом для одного поля. Поэтому использование временной таблицы, наполненной из ТЗ, является стандартным и наиболее правильным подходом.

Заключение

Мы рассмотрели мощный инструмент языка запросов 1С — отбор по кортежам полей. Подведем итоги: использование конструкции (Поле1, Поле2) В (ВЫБРАТЬ...) является более предпочтительным, чем использование внутренних соединений или нагромождение условий ИЛИ. Это обеспечивает чистоту кода, отсутствие дублей в результате и высокую скорость работы, особенно при использовании в параметрах виртуальных таблиц. Применяйте этот метод в своих разработках, чтобы сделать код более профессиональным и эффективным.

← На главную