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