Разработка и Конфигурация · 12 мин
Как выбрать первое значение в запросе 1С
Как выбрать первое значение в запросе 1С: конструкция ПЕРВЫЕ 1, сортировка, МАКСИМУМ, обход выборки. Примеры кода, типичные ошибки и FAQ для разработчика.
Задача получить из запроса только одно — первое — значение встречается в 1С постоянно: найти последнюю цену товара, актуального ответственного сотрудника, самый свежий документ по контрагенту. Язык запросов 1С не имеет аналога функции FIRST_VALUE в чистом виде, поэтому разработчики используют несколько рабочих приёмов: конструкцию ПЕРВЫЕ 1, агрегатные функции МАКСИМУМ и МИНИМУМ, а также программный обход выборки с остановкой на первой строке.
Выбор способа зависит от того, что именно понимается под «первым»: первая строка по заданной сортировке, максимальное значение поля или просто любая одна запись из набора. Неправильно выбранный приём приводит либо к лишним обращениям к базе, либо к непредсказуемому результату, когда «первое» значение оказывается случайным.
Ниже разобраны основные подходы с примерами кода, условиями применения и типичными ошибками. Все примеры применимы к управляемым и обычным формам на платформе 8.3, синтаксис запросов одинаков для большинства типовых конфигураций.
Конструкция ПЕРВЫЕ 1 — основной способ
Ключевое слово ПЕРВЫЕ ограничивает количество строк, возвращаемых запросом. Записывается сразу после ВЫБРАТЬ:
ВЫБРАТЬ ПЕРВЫЕ 1
Товары.Ссылка КАК Товар,
Товары.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Товары
ГДЕ
НЕ Товары.ПометкаУдаления
Такой запрос вернёт ровно одну строку (или ни одной, если таблица пуста). Однако без предложения УПОРЯДОЧИТЬ ПО СУБД сама решает, какая строка окажется первой — порядок зависит от плана выполнения запроса и может меняться от вызова к вызову. Поэтому ПЕРВЫЕ 1 почти всегда сочетают с сортировкой.
Пример: получить самый дорогой товар по таблице цен.
ВЫБРАТЬ ПЕРВЫЕ 1
Цены.Номенклатура КАК Товар,
Цены.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
ГДЕ
Цены.Номенклатура = &Номенклатура
УПОРЯДОЧИТЬ ПО
Цена УБЫВ
Ключевое слово УБЫВ задаёт сортировку по убыванию, поэтому первой строкой станет запись с максимальной ценой. Если нужна минимальная цена — сортировку по убыванию просто убирают (по умолчанию сортировка возрастающая).
Выбор первого значения по дате: последний документ или запись
Самый частый практический сценарий — получить последнюю по времени запись: актуальную цену, курс валюты, кадровое назначение сотрудника. Здесь сортировка строится по полю периода или даты документа в порядке убывания.
Пример для периодического регистра сведений — актуальное значение на дату:
ВЫБРАТЬ ПЕРВЫЕ 1
Курсы.Курс КАК Курс
ИЗ
РегистрСведений.КурсыВалют КАК Курсы
ГДЕ
Курсы.Валюта = &Валюта
И Курсы.Период <= &ДатаКурса
УПОРЯДОЧИТЬ ПО
Курсы.Период УБЫВ
Для документов сортировку по одной дате недостаточно: в пределах одной секунды может быть несколько документов. Надёжнее упорядочить по моменту времени — в запросе это делается через сортировку по ссылке с использованием функции МОМЕНТВРЕМЕНИ либо просто по полю Дата с добавлением Ссылка как второго критерия, если точность до секунды допустима.
Если записей несколько с одинаковым ключом сортировки, добавьте второй уровень упорядочивания, чтобы результат был детерминированным:
УПОРЯДОЧИТЬ ПО
Цены.Период УБЫВ,
Цены.Регистратор УБЫВ
Альтернатива: МАКСИМУМ и МИНИМУМ
Если «первое значение» означает «максимальное» или «минимальное», агрегатные функции часто проще и быстрее, чем сортировка с ограничением строк. Запрос сразу возвращает одно значение без выборки лишних данных:
ВЫБРАТЬ
МАКСИМУМ(Цены.Цена) КАК МаксЦена
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
ГДЕ
Цены.Номенклатура = &Номенклатура
Ограничение подхода: агрегат возвращает только само значение, но не связанную с ним строку. Если нужно узнать, к какому товару относится максимальная цена, придётся либо использовать ПЕРВЫЕ 1 с сортировкой, либо делать второй запрос по найденному значению, либо группировать с соединением.
Сравнение вариантов
Возвращает всю строку целиком. Подходит, когда нужны несколько полей первой записи. Требует явной сортировки.
Возвращает одно скалярное значение. Быстро и просто, но нельзя получить сопутствующие поля той же строки.
Виртуальная таблица периодических регистров сведений. Оптимальна для «актуального значения на дату», но применима только к регистрам сведений.
Гибкий программный вариант: первая строка читается в цикле, затем цикл прерывается. Удобен, когда логика сложнее одного запроса.
Программное получение первой строки выборки
Когда запрос уже написан и менять его нежелательно, первую строку можно взять программно — на стороне встроенного языка. Есть два типовых приёма.
Первый — обход выборки с немедленным прерыванием:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
| Товары.Ссылка КАК Товар
|ИЗ
| Справочник.Номенклатура КАК Товары
|УПОРЯДОЧИТЬ ПО
| Товары.Наименование";
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
НайденныйТовар = Выборка.Товар;
Иначе
НайденныйТовар = Неопределено;
КонецЕсли;
Второй — через выгрузку результата в таблицу значений и обращение к нулевой строке:
Результат = Запрос.Выполнить().Выгрузить();
Если Результат.Количество() > 0 Тогда
НайденныйТовар = Результат[0].Товар;
КонецЕсли;
Обязательно проверяйте, что результат не пуст: обращение к Результат[0] при пустой таблице вызовет ошибку «Индекс находится за границами массива». Проверка Выборка.Следующий() в первом варианте выполняет ту же роль.
- 1Определите, что считать первым значением: минимум, максимум или первая строка по сортировке.
- 2Добавьте в запрос ПЕРВЫЕ 1 после ВЫБРАТЬ.
- 3Добавьте УПОРЯДОЧИТЬ ПО с нужным полем и направлением (УБЫВ для максимального).
- 4Выполните запрос и проверьте результат на пустоту перед обращением к строке.
- 5Протестируйте на данных с одинаковыми значениями ключа сортировки — при необходимости добавьте второй критерий упорядочивания.
Первое значение в группировке: по одному на каждую группу
Отдельная задача — получить первое значение не по всей таблице, а внутри каждой группы: например, последний документ по каждому контрагенту. Одиночным ПЕРВЫЕ 1 это не решается, потому что ограничение действует на весь результат.
Типовое решение — двухшаговый запрос: сначала группировкой находят максимальную дату по каждой группе, затем соединяют её с исходной таблицей, чтобы получить остальные поля:
ВЫБРАТЬ
Док.Контрагент КАК Контрагент,
МАКСИМУМ(Док.Дата) КАК ПоследняяДата
ПОМЕСТИТЬ МаксДаты
ИЗ
Документ.РеализацияТоваровУслуг КАК Док
ГДЕ
Док.Проведен
СГРУППИРОВАТЬ ПО
Док.Контрагент
;
ВЫБРАТЬ
Док.Контрагент КАК Контрагент,
Док.Ссылка КАК ПоследнийДокумент
ИЗ
Документ.РеализацияТоваровУслуг КАК Док
ВНУТРЕННЕЕ СОЕДИНЕНИЕ МаксДаты КАК М
ПО Док.Контрагент = М.Контрагент
И Док.Дата = М.ПоследняяДата
Учтите: если у контрагента два документа с одинаковой датой, соединение вернёт оба. Для строго одного документа на группу добавьте во второй запрос группировку с МАКСИМУМ(Док.Ссылка) или дополнительный критерий по моменту времени.
В консоли запросов удобно проверять конструкцию ПЕРВЫЕ 1 до переноса в код: сначала выполните запрос без ограничения и посмотрите первые строки с заданной сортировкой, затем добавьте ПЕРВЫЕ 1 и убедитесь, что возвращается именно ожидаемая запись.
Производительность и ограничения
Конструкция ПЕРВЫЕ 1 транслируется в TOP 1 на MS SQL Server и аналогичные ограничения на других СУБД. При наличии индекса по полю сортировки сервер может остановить сканирование после первой подходящей строки — это быстро. Без индекса потребуется полная сортировка выборки, что на больших таблицах ощутимо.
Несколько практических ограничений, о которых стоит помнить:
ПЕРВЫЕнельзя применять во вложенных запросах и временных таблицах пакета — только в итоговом запросе выборки. Во вложенном запросе используйте агрегаты или перенесите ограничение на внешний уровень.- Сортировка по полям типа
Строканеограниченной длины в запросе невозможна — такое поле нельзя использовать вУПОРЯДОЧИТЬ ПО. - При обращении к виртуальным таблицам регистров
ПЕРВЫЕ 1не отменяет необходимости задавать параметры виртуальной таблицы (период, условия) — без них выборка будет строиться по всей таблице. - В динамических списках форм
ПЕРВЫЕв произвольном запросе может конфликтовать с механизмами постраничного вывода — проверяйте поведение списка после изменения текста запроса.
Проверка результата
После внедрения запроса убедитесь, что он стабильно возвращает ожидаемое значение. Минимальный набор проверок: выполните запрос на тестовой копии базы с данными, где известен правильный ответ; проверьте случай пустой выборки (условие не находит ни одной записи); проверьте случай нескольких записей с одинаковым ключом сортировки.
Дополнительно полезно сравнить результат ПЕРВЫЕ 1 с результатом альтернативного способа — например, с МАКСИМУМ по тому же полю. Совпадение значений подтверждает корректность сортировки.
Как проверить результат
Всегда возвращает одну и ту же строку при неизменных данных
Результат меняется между выполнениями — сортировка недетерминирована
Код корректно обрабатывает отсутствие строк (проверка Следующий() или Количество())
Ошибка обращения по индексу или Неопределено попадает в дальнейшую логику без контроля
Значение первого поля совпадает с агрегатом по тому же условию
Расхождение — неверно выбрано направление сортировки или условие отбора
Часто задаваемые вопросы
Чем ПЕРВЫЕ 1 отличается от РАЗЛИЧНЫЕ?
ПЕРВЫЕ ограничивает количество возвращаемых строк, а РАЗЛИЧНЫЕ убирает дубликаты из всего результата. Это независимые конструкции: можно написать ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1, чтобы получить одну уникальную строку, но чаще они решают разные задачи.
Можно ли выбрать первые N значений, а не одно?
Да, число после ПЕРВЫЕ произвольное: ПЕРВЫЕ 10 вернёт десять строк по заданной сортировке. Это стандартный приём для топ-списков — например, десяти самых продаваемых товаров.
Как получить первое непустое значение поля?
Добавьте в условие отбор на заполненность: например, ГДЕ Товары.Артикул <> "" для строкового поля или проверку на NULL через НЕ ... ЕСТЬ NULL. После этого ПЕРВЫЕ 1 с сортировкой вернёт первую строку с заполненным значением.
Почему запрос с ПЕРВЫЕ 1 возвращает разные значения при каждом выполнении?
Почти всегда причина в отсутствии или недостаточности сортировки: несколько строк имеют одинаковое значение поля упорядочивания, и СУБД выбирает любую из них. Добавьте уникальный второй критерий сортировки — например, ссылку или код.
Что быстрее: ПЕРВЫЕ 1 с сортировкой или МАКСИМУМ?
Для получения одного скалярного значения МАКСИМУМ обычно эффективнее, так как не требует сортировки всей выборки. Но если нужны другие поля той же строки, ПЕРВЫЕ 1 с сортировкой по индексированному полю — правильный и достаточно быстрый вариант.
Работает ли ПЕРВЫЕ в запросах к табличным частям документов?
Да, табличные части доступны в запросах как обычные таблицы (например, Документ.РеализацияТоваровУслуг.Товары), и ПЕРВЫЕ 1 с сортировкой по номеру строки вернёт первую строку табличной части.
Что важно запомнить
Первое значение в запросе 1С выбирают конструкцией ПЕРВЫЕ 1 в паре с УПОРЯДОЧИТЬ ПО — без сортировки результат непредсказуем. Для скалярного максимума или минимума используйте агрегаты, для периодических регистров — СрезПоследних, а программно первую строку берут через Выборка.Следующий() или Результат[0] с обязательной проверкой на пустоту.