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