Разработка и Конфигурация · 11 мин
Как задать счет в запросе 1С
Как задать счет в запросе 1С: функция АВТОНОМЕРЗАПИСИ, нумерация строк через временные таблицы, подсчет итогов. Примеры кода, ошибки и проверка результата.
Под «счетом» в запросе 1С обычно понимают одну из трех задач: пронумеровать строки результата, посчитать количество записей по условию или получить накопительный итог. Для каждой задачи в языке запросов есть свой инструмент, и смешение этих подходов — самая частая причина ошибок у начинающих разработчиков.
Язык запросов 1С не имеет классических переменных и циклов, поэтому «счетчик» в привычном понимании реализуется либо встроенной функцией АВТОНОМЕРЗАПИСИ(), либо агрегатной функцией КОЛИЧЕСТВО(), либо приемом с самосоединением таблицы. Ниже разобраны все три сценария с примерами кода и способами проверки результата.
Материал ориентирован на платформу 1С:Предприятие 8.3, где доступна функция авто нумерации записей в запросе. Для более старых версий приведен обходной вариант через временные таблицы.
Что именно вы хотите посчитать: три разные задачи
Прежде чем писать запрос, определите, какой результат нужен. Первая задача — порядковый номер строки в выборке: например, вывести список товаров с колонкой «№ п/п» для печатной формы. Вторая — количество записей, удовлетворяющих условию: сколько документов проведено за период. Третья — накопительный итог или номер внутри группы: нумерация строк табличной части каждого документа отдельно.
Эти задачи решаются разными средствами, и попытка применить АВТОНОМЕРЗАПИСИ() там, где нужна группировка, даст номер, который не соответствует логике отчета. Ниже каждый вариант разобран отдельно.
Как выбрать действие
Нумерация строк результата функцией АВТОНОМЕРЗАПИСИ()
Функция АВТОНОМЕРЗАПИСИ() возвращает целое число — порядковый номер записи в результате запроса, начиная с единицы. Она указывается непосредственно в списке выбираемых полей и не требует параметров.
ВЫБРАТЬ
АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
Товары.Ссылка КАК Номенклатура,
Товары.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Товары
ГДЕ
НЕ Товары.ПометкаУдаления
УПОРЯДОЧИТЬ ПО
Товары.Наименование
Обратите внимание на важную особенность: нумерация присваивается после применения упорядочивания, поэтому номера идут в том порядке, в котором строки выводятся. Однако если результат запроса затем выгружается в таблицу значений и сортируется заново в коде, номера «поедут» — они зафиксированы на момент выполнения запроса.
Функцию нельзя использовать в секции ГДЕ, в итогах и внутри агрегатных выражений. Она работает только как поле выборки. Если требуется отфильтровать строки по номеру (например, взять первые десять), используйте конструкцию ВЫБРАТЬ ПЕРВЫЕ 10 вместо условия по номеру.
Подсчет количества записей функцией КОЛИЧЕСТВО()
Если под «счетом» понимается количество записей, используйте агрегатную функцию КОЛИЧЕСТВО(). Вариант КОЛИЧЕСТВО(*) считает все строки, КОЛИЧЕСТВО(Поле) — строки, где поле не равно NULL, а КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) — число уникальных значений.
ВЫБРАТЬ
РеализацияТоваров.Контрагент КАК Контрагент,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РеализацияТоваров.Ссылка) КАК КоличествоДокументов
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваров
ГДЕ
РеализацияТоваров.Проведен
СГРУППИРОВАТЬ ПО
РеализацияТоваров.Контрагент
Такой запрос вернет по каждому контрагенту число проведенных реализаций. Если нужно общее количество без разбивки, уберите группировку и оставьте только агрегатное поле — запрос вернет одну строку с одним числом.
Типичная тонкость: при соединении таблиц КОЛИЧЕСТВО(*) может вернуть завышенное число из-за размножения строк. В таких случаях всегда считайте РАЗЛИЧНЫЕ ссылки, а не все строки выборки.
Нумерация внутри групп через временные таблицы
АВТОНОМЕРЗАПИСИ() нумерует весь результат сквозным образом. Если нужно, чтобы нумерация начиналась заново для каждого документа или каждого контрагента, потребуется прием с самосоединением: для каждой строки подсчитывается количество строк той же группы, у которых ключ упорядочивания меньше или равен текущему.
ВЫБРАТЬ
Таб.Ссылка КАК Документ,
Таб.Номенклатура КАК Номенклатура,
Таб.НомерСтроки КАК НомерСтроки
ПОМЕСТИТЬ ВТ_Строки
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Таб
;
ВЫБРАТЬ
Т1.Документ КАК Документ,
Т1.Номенклатура КАК Номенклатура,
КОЛИЧЕСТВО(Т2.НомерСтроки) КАК ПорядковыйНомер
ИЗ
ВТ_Строки КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Строки КАК Т2
ПО Т1.Документ = Т2.Документ
И Т1.НомерСтроки >= Т2.НомерСтроки
СГРУППИРОВАТЬ ПО
Т1.Документ,
Т1.Номенклатура,
Т1.НомерСтроки
Этот прием рабочий, но ресурсоемкий: для каждой строки выполняется сравнение со всеми строками группы. На табличных частях документов это не критично, но на больших регистрах с сотнями тысяч записей запрос может выполняться долго. В таких случаях нумерацию дешевле выполнить уже в коде при обходе выборки.
Накопительный итог (счет с нарастанием) в запросе
Накопительный итог — это когда для каждой строки выводится сумма всех предыдущих значений плюс текущее. В чистом языке запросов 1С это решается тем же приемом самосоединения, только вместо КОЛИЧЕСТВО() применяется СУММА() по значениям «предыдущих» строк.
ВЫБРАТЬ
Т1.Период КАК Период,
Т1.Сумма КАК Сумма,
СУММА(Т2.Сумма) КАК СуммаНарастающимИтогом
ИЗ
ВТ_Обороты КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Обороты КАК Т2
ПО Т1.Период >= Т2.Период
СГРУППИРОВАТЬ ПО
Т1.Период,
Т1.Сумма
УПОРЯДОЧИТЬ ПО
Т1.Период
Альтернатива без запроса — обойти выборку в коде и накапливать сумму в переменной. Для отчетов на СКД накопительный итог можно получить функцией ВычислитьВыражение с параметрами обхода, что обычно быстрее самосоединения.
Сравнение вариантов
Быстро и просто, но только сквозная нумерация всего результата, без групп и условий
Гибко: номера внутри групп и нарастающие итоги, но медленно на больших объемах
Полный контроль и хорошая скорость, но логика уходит из запроса в модуль
Подходит для отчетов, требует знакомства с языком выражений СКД
Задание счета через параметры и выражения в запросе
Иногда под «задать счет» понимают передачу в запрос начального значения или условия отбора по счету бухгалтерского учета. В этом случае используются параметры запроса: знак амперсанда в тексте и метод УстановитьПараметр в коде.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Субконто1 КАК Контрагент,
| ХозрасчетныйОстатки.СуммаОстаток КАК Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = &Счет, , ) КАК ХозрасчетныйОстатки";
Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.РасчетыСПокупателями);
Если нужно отобрать по группе счетов (например, все субсчета 60-го), используйте условие Счет В ИЕРАРХИИ(&Счет). Это корректно отработает и при наличии субсчетов второго уровня, и при их отсутствии.
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.НайтиПоКоду("60"));Проверка результата и типичные ошибки
После написания запроса проверьте результат на контрольном примере с заранее известным ответом. Для нумерации — выгрузите результат в таблицу значений и убедитесь, что номера идут подряд без пропусков и дублей. Для КОЛИЧЕСТВО — сверьте итог с ручным подсчетом в списке документов или с данными универсального отчета.
Отдельно проверьте поведение на пустой выборке: запрос с КОЛИЧЕСТВО без группировки вернет одну строку со значением 0, а запрос с группировкой не вернет ни одной строки. Код, который ожидает хотя бы одну запись, должен это учитывать через проверку ПустойРезультат или количества строк выгрузки.
Как проверить результат
Номера идут от 1 подряд, без пропусков и повторов
Пропуски или дубли номеров — значит, в выборке есть соединения, размножающие строки
Совпадает с ручным подсчетом по списку объектов
Число больше ожидаемого — вероятно, нужно РАЗЛИЧНЫЕ
В результат попадают только проводки по нужному счету и его субсчетам
Пустой результат при заведомо существующих данных — проверьте тип параметра
Запрос отрабатывает за секунды на рабочем объеме данных
Резкое замедление при росте таблицы — признак квадратичного самосоединения
Частые вопросы
Можно ли начать нумерацию АВТОНОМЕРЗАПИСИ() не с единицы?
Напрямую нельзя — функция всегда начинает с 1. Обходной путь: прибавить смещение в выражении поля, например АВТОНОМЕРЗАПИСИ() + 100, или вычесть нужное значение. Либо выполнить нумерацию в коде при обходе выборки с произвольным начальным значением.
Работает ли АВТОНОМЕРЗАПИСИ() в запросах СКД?
Да, функцию можно использовать в запросе набора данных схемы компоновки. Однако для отчетов часто удобнее вычисляемое поле или нумерация в макете, потому что группировки СКД могут менять порядок и состав строк после выполнения запроса.
Как посчитать количество строк табличной части документа запросом?
Выберите КОЛИЧЕСТВО(НомерСтроки) из табличной части с группировкой по ссылке на документ и условием по конкретному документу. Альтернатива без запроса — свойство Количество() у коллекции табличной части в коде, если объект уже получен.
Почему запрос с условием по счету возвращает пустой результат?
Чаще всего параметр передан не тем типом: строкой или кодом вместо ссылки на план счетов. Получите ссылку через ПланыСчетов.Хозрасчетный.НайтиПоКоду("60") и проверьте, что она не пустая, прежде чем передавать в запрос.
Что быстрее: нумерация в запросе или в коде?
АВТОНОМЕРЗАПИСИ() выполняется на стороне СУБД практически бесплатно и быстрее обхода в коде. А вот нумерацию внутри групп через самосоединение на больших объемах выгоднее делать в коде: один проход по упорядоченной выборке со сбросом счетчика при смене группы работает за линейное время.
Что важно запомнить
Сквозная нумерация строк — АВТОНОМЕРЗАПИСИ() в списке полей. Подсчет записей — КОЛИЧЕСТВО() с группировкой и РАЗЛИЧНЫЕ при соединениях. Нумерация внутри групп и нарастающий итог — самосоединение или обход в коде. Отбор по счету бухгалтерии — параметр со ссылкой плана счетов и условие В ИЕРАРХИИ для субсчетов.