При работе с переписанными конфигурациями на базе 1С:Управление торговлей 10.3 часто возникает необходимость оперативного изменения логики выгрузки данных, например, при отправке прайс-листов. Одной из типичных задач является исключение определенной номенклатуры из отчета на основе свойств, хранящихся в связанных справочниках. Рассмотрим, как правильно модифицировать запрос, чтобы отсечь товары с определенным цветом, и проанализируем основные ошибки, возникающие при этом.
В нашем распоряжении имеется запрос, который выбирает остатки товаров из регистра накопления ТоварыНаСкладах.Остатки и соединяет их с актуальными ценами из регистра сведений ЦеныНоменклатуры.СрезПоследних. Нам необходимо добавить условие: если у номенклатуры выбран цвет с определенным кодом (например, 000000003), она не должна попадать в результат.
Проанализируем структуру типового запроса для решения этой задачи. Важно помнить, что в 1С фильтры по ссылочным полям лучше всего устанавливать непосредственно в параметрах виртуальной таблицы. Это существенно повышает производительность системы, так как отсечение данных происходит на уровне СУБД еще до начала формирования основной выборки.
Рассмотрим наиболее правильный с точки зрения архитектуры 1С способ решения проблемы. Мы установим фильтр прямо в скобках виртуальной таблицы Остатки(). Для этого нам потребуется заранее найти нужный элемент справочника по коду и передать его в запрос как параметр.
// 1. Сначала находим нужный цвет по коду
НужныйЦвет = Справочники.Цвета.НайтиПоКоду("000000003");
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| СУММА(ТоварыНаСкладахОстатки.КоличествоОстаток) КАК Остаток,
| ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена,
| ТоварыНаСкладахОстатки.Номенклатура.Артикул КАК Артикул,
| ТоварыНаСкладахОстатки.Номенклатура.Производитель КАК Производитель
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| &Период,
| Склад В (&Склады)
| И НЕ Номенклатура.Цвет = &Цвет
| И НЕ Номенклатура В ИЕРАРХИИ (&ИсключаемаяГруппа)
| ) КАК ТоварыНаСкладахОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен) КАК ЦеныНоменклатурыСрезПоследних
| ПО ТоварыНаСкладахОстатки.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
|СГРУППИРОВАТЬ ПО
| ТоварыНаСкладахОстатки.Номенклатура,
| ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0),
| ТоварыНаСкладахОстатки.Номенклатура.Артикул,
| ТоварыНаСкладахОстатки.Номенклатура.Производитель
|УПОРЯДОЧИТЬ ПО
| Номенклатура";
Запрос.УстановитьПараметр("Цвет", НужныйЦвет);
Запрос.УстановитьПараметр("Склады", МассивСкладов);
Запрос.УстановитьПараметр("ТипЦен", РозничнаяЦена);
Запрос.УстановитьПараметр("ИсключаемаяГруппа", Справочники.Номенклатура.НайтиПоКоду("00000099105"));
В данном примере мы используем конструкцию НЕ Номенклатура.Цвет = &Цвет внутри параметров виртуальной таблицы. Обратите внимание, что если реквизит Цвет в вашей конфигурации находится не в самой Номенклатуре, а в подчиненном справочнике, логика запроса потребует использования временных таблиц.
Если справочник Цвета является подчиненным по отношению к номенклатуре, то простое обращение через точку может не сработать. В этом случае мы сначала соберем весь список номенклатуры, обладающей "нежелательным" цветом, во временную таблицу, а затем исключим её из основного запроса.
Проанализируем этот подход по шагам:
ТаблицаЗеленых.НЕ Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ТаблицаЗеленых).
Запрос.Текст = "ВЫБРАТЬ
| Цвета.Владелец КАК Номенклатура
|ПОМЕСТИТЬ ТаблицаЗеленых
|ИЗ
| Справочник.Цвета КАК Цвета
|ГДЕ
| Цвета.Код = ""000000003""
|;
|
|ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток,
| ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
| ПО ТоварыНаСкладахОстатки.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
|ГДЕ
| НЕ ТоварыНаСкладахОстатки.Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ТаблицаЗеленых)";
Разберем ситуацию, когда вы добавили код, но "зеленые" товары все равно попадают в прайс или, наоборот, пропадает слишком много позиций. Выясним основные причины:
1. Ошибка поиска по коду. Метод НайтиПоКоду("000000003") чувствителен к длине строки. Если в справочнике код имеет длину 11 символов, а вы ищете 9, система вернет ПустуюСсылку. В результате условие НЕ Номенклатура.Цвет = &Цвет превратится в "Цвет не равен пустоте", что пропустит все заполненные карточки. Всегда проверяйте результат поиска: Если НужныйЦвет.Пустая() Тогда Сообщить("Цвет не найден!"); КонецЕсли;.
2. Проблема иерархии. Использование НЕ Номенклатура В ИЕРАРХИИ (&Номенклатура) при пустом параметре может привести к непредсказуемым результатам — иногда 1С исключает всю номенклатуру без родителя (корневые элементы). Если исключение групп не требуется, это условие лучше убрать.
3. Использование характеристик. В типовой УТ 10.3 цвет часто выносят в Характеристики номенклатуры. Если это так, то фильтровать нужно не Номенклатура.Цвет, а ХарактеристикаНоменклатуры.Цвет (или другое свойство). Проверьте в конфигураторе, где именно в регистре ТоварыНаСкладах хранится информация о цвете — в измерении Номенклатура или ХарактеристикаНоменклатуры.
4. Регистрозависимость при использовании ПОДОБНО. Если вы решили фильтровать по наименованию (Цвет.Наименование ПОДОБНО "%Зеленый%"), помните, что "Зеленый" и "зеленый" для SQL-сервера могут быть разными значениями. Кроме того, лишние пробелы в названии (как в случае автора темы: "Зеленый заказной") сделают фильтрацию некорректной.
При работе с большими базами данных 1С следует придерживаться следующих правил при написании запросов:
ЕСТЬNULL(), чтобы избежать ошибок при вычислениях или группировке.СГРУППИРОВАТЬ ПО, убедитесь, что все поля выборки, к которым не применяются агрегатные функции (как СУММА), перечислены в секции группировки.ЛЕВОЕ СОЕДИНЕНИЕ с виртуальной таблицей СрезПоследних без указания периода может работать медленно. Если отчет строится на текущую дату, желательно передавать параметр ТекущаяДата().Проанализировав все способы, мы пришли к выводу, что для решения задачи в УТ 10.3 оптимально использовать фильтр в параметрах виртуальной таблицы остатков, предварительно убедившись, что искомый элемент справочника найден по коду и корректно передан в запрос.