В практике разработки на платформе 1С:Предприятие часто встречается ситуация, когда данные распределены по нескольким регистрам, имеющим схожую структуру. Например, если для каждой группы товаров (колбасы, доски, игрушки) был создан отдельный регистр цен. С точки зрения архитектуры это не всегда оптимально, но если задача стоит получить данные из существующих объектов, нам необходимо разобраться, как сделать это эффективно и универсально.
В этой статье мы разберем несколько способов решения: от простого объединения таблиц в конструкторе запросов до динамического формирования текста запроса на основе метаданных. Также мы рассмотрим, почему объединение регистров в один является лучшим долгосрочным решением.
Самый очевидный и простой для понимания способ — это написание одного запроса, который собирает данные из виртуальных таблиц СрезПоследних каждого регистра и объединяет их в одну результирующую таблицу. Рассмотрим этот процесс по шагам.
Допустим, у нас есть три регистра: ЦенаПроизводстваКолбас, ЦенаПроизводстваДосок и ЦенаПроизводстваИгрушек. Все они имеют измерение Номенклатура и ресурс Цена.
Проанализируем структуру запроса:
ВЫБРАТЬ
"Колбасы" КАК Категория,
СрезКолбас.Номенклатура КАК Номенклатура,
СрезКолбас.Цена КАК Цена
ИЗ
РегистрСведений.ЦенаПроизводстваКолбас.СрезПоследних(&Период, ) КАК СрезКолбас
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Доски",
СрезДосок.Номенклатура,
СрезДосок.Цена
ИЗ
РегистрСведений.ЦенаПроизводстваДосок.SрезПоследних(&Период, ) КАК СрезДосок
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Игрушки",
СрезИгрушек.Номенклатура,
СрезИгрушек.Цена
ИЗ
РегистрСведений.ЦенаПроизводстваИгрушек.СрезПоследних(&Период, ) КАК СрезИгрушек
При использовании этого метода важно помнить о следующих правилах:
Номенклатура — это справочник, а в другом — строка (что бывает крайне редко, но случается), запрос может вернуть ошибку или работать некорректно.ОБЪЕДИНИТЬ должно быть одинаковым.Если количество регистров велико или они постоянно добавляются, писать запрос вручную неудобно. Мы можем использовать встроенный язык 1С для автоматической генерации текста запроса. Этот подход является более универсальным.
Рассмотрим пример кода, который перебирает все регистры сведений, чье имя начинается с определенного префикса, и формирует единый запрос:
ТекстЗапроса = "";
ПервыйРегистр = Истина;
Для Каждого Рег Из Метаданные.РегистрыСведений Цикл
Если СтрНачинаетсяС(Рег.Имя, "ЦенаПроизводства") Тогда
Если Не ПервыйРегистр Тогда
ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
КонецЕсли;
ТекстЗапроса = ТекстЗапроса +
"ВЫБРАТЬ Номенклатура, Цена, """ + Рег.Имя + """ КАК Источник
|ИЗ РегистрСведений." + Рег.Имя + ".СрезПоследних(&Период, )";
ПервыйРегистр = Ложь;
КонецЕсли;
КонецЦикла;
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Результат = Запрос.Выполнить().Выгрузить();
Выясним причину эффективности этого метода: нам не нужно знать точный список регистров заранее. Если завтра появится регистр ЦенаПроизводстваМороженого, код подхватит его автоматически без изменений в конфигураторе.
Когда мы работаем с виртуальными таблицами СрезПоследних внутри объединения, система выполняет сложную операцию поиска последней записи для каждого регистра в отдельности. Если нам нужно дополнительно фильтровать данные или соединять их с другими таблицами, лучше сначала поместить результаты во временную таблицу.
Разберем по шагам, как это сделать:
ПОМЕСТИТЬ ВТ_ВсеЦены.ВТ_ВсеЦены, где уже можно легко выполнять сортировку, группировку или левое соединение с остатками товаров.
ВЫБРАТЬ
Срез.Номенклатура КАК Номенклатура,
Срез.Цена КАК Цена
ПОМЕСТИТЬ ВТ_ОбщиеЦены
ИЗ
РегистрСведений.Цена1.СрезПоследних(&Период, ) КАК Срез
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Срез2.Номенклатура,
Срез2.Цена
ИЗ
РегистрСведений.Цена2.СрезПоследних(&Период, ) КАК Срез2;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.Номенклатура,
ВТ.Цена,
СпрНоменклатура.Артикул
ИЗ
ВТ_ОбщиеЦены КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
ПО ВТ.Номенклатура = СпрНоменклатура.Ссылка
Проанализируем ситуацию, описанную в теме. Создание отдельных регистров для каждого вида продукции — это архитектурная ошибка. Вот основные проблемы, к которым она приводит:
Решение: Объединить все данные в один регистр ЦеныПроизводства. Чтобы разделять данные, достаточно добавить новое измерение ВидПродукции (используя СправочникСсылка.ВидыНоменклатуры или ПеречислениеСсылка). Тогда запрос на получение всех цен станет максимально простым:
ВЫБРАТЬ
Цены.Номенклатура,
Цены.Цена
ИЗ
РегистрСведений.ЦеныПроизводства.СрезПоследних(&Период, ) КАК Цены
ГДЕ
Цены.ВидПродукции = &НужныйВид
Если вы столкнулись с необходимостью собирать данные из множества регистров, используйте динамическое формирование текста запроса для обеспечения универсальности. Однако, если у вас есть возможность влиять на структуру базы данных, настоятельно рекомендуем выполнить рефакторинг и объединить эти регистры в один с дополнительным измерением. Это значительно упростит поддержку кода и повысит производительность системы в будущем.