A1sCode библиотека 1С

A1sQ.FirstRowQ

Назначение: получить первую строку результата запроса одной функцией.
Проблема: стандартно нужны 3–4 строчки кода с проверками и обработкой ошибок.
Решение: FirstRowQ выполняет запрос, делает Следующий(), и возвращает уже позиционированную выборку или Неопределено.
Идеально для: быстрого чтения «шапки» документа, проверки дублей, получения «последнего/первого» элемента, компактной валидации. минимум кодабезопасночитабельно

Сигнатура

Function FirstRowQ(
    QueryText,
    Value1 = Undefined, Value2 = Undefined, Value3 = Undefined, Value4 = Undefined,
    Value5 = Undefined, Value6 = Undefined, Value7 = Undefined, Value8 = Undefined,
    TempTablesManager = Undefined
) Export

Параметры

  • QueryText — текст запроса 1С (или генератор через A1sQ.QT).
  • Value1..Value8 — позиционные значения для параметров &Парам по порядку появления.
  • TempTablesManager — менеджер временных таблиц (опционально).

Возвращаемое значение

ВыборкаИзРезультатаЗапроса, уже позиционированная на первой записи; либо Неопределено, если записей нет/возникла ошибка.

Пошаговая логика

Функция FirstRowQ(QueryText, Value1 = Неопределено, Value2 = Неопределено, Value3 = Неопределено,
                  Value4 = Неопределено, Value5 = Неопределено, Value6 = Неопределено,
                  Value7 = Неопределено, Value8 = Неопределено, TempTablesManager = Неопределено) Экспорт

    Попытка // 1) Защищенное выполнение
        // 2) Выполняем запрос через общий конвейер ExecuteQ()
        Выборка = ExecuteQ(QueryText, Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8, TempTablesManager);

        // 3) Проверяем наличие данных (позиционируемся на первой записи)
        Если Выборка.Следующий() Тогда
            Возврат Выборка; // уже стоит на первой строке
        КонецЕсли;

    Исключение
        // 4) Любая ошибка логируется и функция возвращает Неопределено
        A1sS.Print("FirstRowQ error: " + ОписаниеОшибки());
    КонецПопытки;

    Возврат Неопределено;
КонецФункции

Примеры

1) Пользователь по УИД

УИД = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;

Row = A1sQ.FirstRowQ("
|ВЫБРАТЬ Ссылка, Наименование, Заблокирован
|ИЗ Справочник.Пользователи
|ГДЕ ИдентификаторПользователяИБ = &UID", УИД);

Если Row <> Неопределено Тогда
    Если Row.Заблокирован Тогда ВызватьИсключение("Пользователь заблокирован!"); КонецЕсли;
    Сообщить("Найден: " + Row.Наименование);
Иначе
    ВызватьИсключение("Пользователь не найден!");
КонецЕсли;

2) Информация об организации

Org = A1sQ.FirstRowQ("
|ВЫБРАТЬ Наименование, ИНН, ЮридическийАдрес
|ИЗ Справочник.Организации
|ГДЕ Ссылка = &Орг", ТекущаяОрганизация);

Заголовок = (Org <> Неопределено) ?
    ("Организация: " + Org.Наименование + " (ИНН: " + Org.ИНН + ")") :
    "Организация не определена";

3) Последний документ (по дате/номеру)

Last = A1sQ.FirstRowQ("
|ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка, Дата, Номер, Сумма
|ИЗ Документ.ПоступлениеТоваровУслуг
|ГДЕ Организация = &Орг
|УПОРЯДОЧИТЬ ПО Дата УБЫВ, Номер УБЫВ", ТекущаяОрганизация);

Если Last <> Неопределено Тогда
    Сообщить("Последнее поступление: №" + Last.Номер
        + " от " + Формат(Last.Дата, "ДФ=dd.MM.yyyy")
        + " на сумму " + Строка(Last.Сумма));
Иначе
    Сообщить("Документы поступления не найдены");
КонецЕсли;

4) Проверка дублей

Дубль = A1sQ.FirstRowQ("
|ВЫБРАТЬ Ссылка, Наименование
|ИЗ Справочник.Номенклатура
|ГДЕ Артикул = &Артикул И Ссылка <> &Ссылка",
НоваяНоменклатура.Артикул, НоваяНоменклатура.Ссылка);

Если Дубль <> Неопределено Тогда
    ВызватьИсключение("Артикул уже используется: " + Дубль.Наименование);
КонецЕсли;

Сравнение: до / после

Без FirstRowQС FirstRowQ
Попытка
    S = A1sQ.ExecuteQ("ВЫБРАТЬ Ссылка, Наименование
                       ИЗ Справочник.Пользователи
                       ГДЕ ИдентификаторПользователяИБ = &UID", УИД);
    Если S.Следующий() Тогда
        Ссылка = S.Ссылка; Имя = S.Наименование;
    Иначе
        Ссылка = Справочники.Пользователи.ПустаяСсылка(); Имя="Не найден";
    КонецЕсли;
Исключение
    A1sS.Print("Ошибка: " + ОписаниеОшибки());
    Ссылка = Справочники.Пользователи.ПустаяСсылка(); Имя="Ошибка";
КонецПопытки;
R = A1sQ.FirstRowQ("ВЫБРАТЬ Ссылка, Наименование
                    ИЗ Справочник.Пользователи
                    ГДЕ ИдентификаторПользователяИБ = &UID", УИД);
Если R <> Неопределено Тогда
    Ссылка = R.Ссылка; Имя = R.Наименование;
Иначе
    Ссылка = Справочники.Пользователи.ПустаяСсылка(); Имя="Не найден";
КонецЕсли;

Паттерны использования

  • «Прочитай и реши»: быстро решаем, продолжать ли обработку, не гоняя весь набор.
  • «Дай шапку»: тянем только ключевые поля первой строки для заголовков форм и сообщений.
  • «Антидубли»: один вызов — одна валидация перед записью.

Особенности и нюансы

✅ Возвращает выборку, УЖЕ позиционированную на первой записи
   • Сразу обращайтесь к полям: Row.Поле1, Row.Поле2
   • НЕ вызывайте Row.Следующий() повторно — иначе уйдете на вторую запись

✅ Автоматическая обработка ошибок
   • Исключения не «падают» наружу — печатаются через A1sS.Print()
   • Возвращаемое значение всегда определено (Выборка или Неопределено)

✅ Поддержка до 8 параметров
   • Передаются позиционно в порядке появления &Param в тексте запроса

❌ Ограничения
   • Только первая строка. Для обхода множества — используйте ExecuteQ/Unload

⚠️ Тонкости
   • Выборка привязана к результату запроса — не храните ее «надолго»
   • Для «последнего» объекта лучше задайте сортировку и ПЕРВЫЕ 1 в запросе

Сравнение с другими функциями A1sQ

// FirstRowQ — когда нужна вся первая строка
Row = A1sQ.FirstRowQ("ВЫБРАТЬ Ссылка, Наименование ИЗ ... ГДЕ ...", Парам);

// ValueQ — когда нужно одно значение/по умолчанию
Имя = A1sQ.ValueQ("ВЫБРАТЬ Наименование ИЗ ... ГДЕ ...", "Не найдено", Парам);

// ExistsQ — когда нужна быстрая проверка существования
Если A1sQ.ExistsQ("ВЫБРАТЬ * ИЗ ... ГДЕ ...", Парам) Тогда ... КонецЕсли;

// ExecuteQ — когда нужно обойти набор строк
S = A1sQ.ExecuteQ("ВЫБРАТЬ ... ИЗ ... ГДЕ ...", Парам);
Пока S.Следующий() Цикл
    // обработка
КонецЦикла;

// Unload — когда нужна таблица значений целиком
ТЗ = A1sQ.Unload("ВЫБРАТЬ ... ИЗ ... ГДЕ ...", Парам);

Типичные ошибки

❌ Повторный вызов Следующий()
Row = A1sQ.FirstRowQ("ВЫБРАТЬ * ИЗ Справочник.Пользователи");
Если Row <> Неопределено Тогда
    // НЕПРАВИЛЬНО:
    Если Row.Следующий() Тогда ... // уйдете на вторую запись!
КонецЕсли;

// ✅ Правильно
Row = A1sQ.FirstRowQ("ВЫБРАТЬ * ИЗ Справочник.Пользователи");
Если Row <> Неопределено Тогда
    Имя = Row.Наименование;
КонецЕсли;

❌ Без проверки на Неопределено
Row = A1sQ.FirstRowQ("ВЫБРАТЬ * ИЗ НесуществующаяТаблица");
Имя = Row.Наименование; // ошибка

// ✅ Правильно
Row = A1sQ.FirstRowQ("ВЫБРАТЬ * ИЗ Справочник.Пользователи");
Имя = (Row <> Неопределено) ? Row.Наименование : "Не найдено";

❌ Перепутанный порядок параметров
Row = A1sQ.FirstRowQ("... ГДЕ Поле1 = &P1 И Поле2 = &P2", Знач2, Знач1);
                   // ^ порядок нарушен!

// ✅ Правильно
Row = A1sQ.FirstRowQ("... ГДЕ Поле1 = &P1 И Поле2 = &P2", Знач1, Знач2);

FAQ

Почему функция возвращает выборку, а не структуру?
Так мы избегаем копирования и дополнительных аллокаций. Вы читаете поля напрямую из курсора.
Можно ли использовать c A1sQ.QT и A1sQ.ExecuteQ?
Да. Передайте текст, собранный через QT, или используйте полноформатный запрос — FirstRowQ сам вызывает ExecuteQ.
Что будет при ошибке синтаксиса?
Ошибка будет залогирована через A1sS.Print, а функция вернет Неопределено.
  • A1sQ.ExistsQ — логический ответ «есть/нет».
  • A1sQ.ValueQ — первое значение с дефолтом.
  • A1sQ.ExecuteQ — выборка для обхода множества строк.