Как выбрать каждую десятую запись из результата запроса в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработчика 1С периодически возникают задачи, связанные с получением ограниченной выборки данных для статистических отчетов, тестирования или децимации (сокращения объема данных без потери структуры). Одной из таких задач является выбор каждой десятой записи из общего массива данных. Например, если в результате запроса получено 600 строк, нам нужно оставить только 60, распределенных равномерно по всему списку.

В этой статье мы подробно разберем, как реализовать этот алгоритм различными способами: от современных функций языка запросов до программной обработки в коде 1С.

Способ 1: Использование функции Автономерзаписи() в языке запросов

Начиная с версии платформы 1С:Предприятие 8.3.20, разработчикам стала доступна встроенная функция Автономерзаписи(). Это наиболее элегантный и производительный способ решения задачи непосредственно на уровне СУБД. Однако важно помнить, что эта функция работает только во временных таблицах.

Проанализируем алгоритм реализации:

  1. Сначала мы выбираем все необходимые данные и помещаем их во временную таблицу. На этом этапе критически важно задать четкую сортировку с помощью УПОРЯДОЧИТЬ ПО, чтобы номера строк были детерминированными.
  2. Во втором запросе мы выбираем данные из временной таблицы, используя функцию Автономерзаписи() и математическую операцию остатка от деления.

Рассмотрим пример кода запроса:


// Первый этап: подготовка данных во временной таблице
ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    Сотрудники.Код КАК Код
ПОМЕСТИТЬ ВТ_ВсеСотрудники
ИЗ
    Справочник.Сотрудники КАК Сотрудники
УПОРЯДОЧИТЬ ПО
    Код;

////////////////////////////////////////////////////////////////////////////////
// Второй этап: выборка каждой 10-й записи
ВЫБРАТЬ
    ВТ_ВсеСотрудники.Сотрудник,
    Автономерзаписи() КАК НомерСтроки
ИЗ
    ВТ_ВсеСотрудники КАК ВТ_ВсеСотрудники
ГДЕ
    (Автономерзаписи() - 1) % 10 = 0

Выясним причину использования конструкции (Автономерзаписи() - 1) % 10 = 0. Функция Автономерзаписи() начинает отсчет с 1. Если нам нужно включить в результат самую первую запись (1-ю, 11-ю, 21-ю и т.д.), мы вычитаем единицу перед делением. Если же нам нужны строго 10-я, 20-я и 30-я записи, условие будет выглядеть как Автономерзаписи() % 10 = 0.

Способ 2: Программная обработка таблицы значений

Если версия платформы ниже 8.3.20 или использование временных таблиц по каким-то причинам нецелесообразно, мы можем прибегнуть к обработке результата запроса в коде. Посмотрим на наиболее эффективный метод — обращение к строкам таблицы значений по индексу.

Разберем по шагам, как это сделать:

  1. Выполняем запрос и выгружаем результат в объект ТаблицаЗначений.
  2. Создаем новую пустую таблицу значений с такой же структурой для хранения результата.
  3. Запускаем цикл, который будет обращаться к каждой десятой строке исходной таблицы.

Посмотрим на пример реализации:


РезультатЗапроса = Запрос.Выполнить();
ТЗ_Полная = РезультатЗапроса.Выгрузить();
ТЗ_Результат = ТЗ_Полная.СкопироватьКолонки();

Шаг = 10;
Для Индекс = 0 По ТЗ_Полная.Количество() - 1 Цикл
    Если Индекс % Шаг = 0 Тогда
        НоваяСтрока = ТЗ_Результат.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, ТЗ_Полная[Индекс]);
    КонецЕсли;
КонецЦикла;

Этот метод прост в понимании, но требует дополнительной памяти для хранения полной копии данных перед фильтрацией. Для выборок в несколько тысяч строк это не критично, но для миллионов записей лучше использовать первый способ.

Способ 3: Использование счетчика при обходе выборки

Если мы хотим сэкономить память и не выгружать весь результат в таблицу значений, можно использовать объект ВыборкаИзРезультатаЗапроса и обычный счетчик. Проанализируем эту ситуацию:


Выборка = Запрос.Выполнить().Выбрать();
Счетчик = 0;

Пока Выборка.Следующий() Цикл
    Счетчик = Счетчик + 1;
    
    // Проверяем, является ли текущая запись десятой
    Если Счетчик % 10 = 1 Тогда 
        // Обрабатываем запись (например, выводим в отчет)
        Сообщить("Сотрудник: " + Выборка.Сотрудник);
    КонецЕсли;
КонецЦикла;

В данном примере условие Счетчик % 10 = 1 позволяет нам обработать 1-ю строку, затем 11-ю и так далее. Это удобно, если данные сразу выводятся в текстовый файл или лог.

Способ 4: Псевдослучайная выборка (Рандомизация)

Иногда задача "каждая десятая" подразумевает не строгий порядок, а получение случайных 10% данных. В 1С нет встроенной функции RANDOM в языке запросов, но мы можем использовать хитрость с уникальными идентификаторами. Выясним, как это работает.

Каждая ссылка в 1С имеет УникальныйИдентификатор. Если привести его к строке и взять из нее несколько символов, мы получим значение, по которому можно отсортировать данные "случайным" образом. Рассмотрим концепцию:


ВЫБРАТЬ ПЕРВЫЕ 10 ПРОЦЕНТОВ
    Сотрудники.Ссылка КАК Сотрудник
ИЗ
    Справочник.Сотрудники КАК Сотрудники
УПОРЯДОЧИТЬ ПО
    ПРЕДСТАВЛЕНИЕ(Сотрудники.Ссылка.УникальныйИдентификатор)

Важное замечание: Сортировка по строковому представлению GUID — ресурсоемкая операция. На больших таблицах это может привести к значительному замедлению работы СУБД, так как серверу придется вычислить это представление для каждой записи перед сортировкой.

Рекомендации и важные моменты

При выборе любого из способов следует учитывать несколько технических нюансов:

Таким образом, выбор метода зависит от вашей версии платформы и объема обрабатываемых данных. Для современных конфигураций оптимальным будет использование Автономерзаписи(), а для простых внешних обработок на старых версиях вполне подойдет программный перебор выборки со счетчиком.

← На главную