Как правильно вывести субконто и их виды в запросе для загрузки в РегистрыБухгалтерии.Хозрасчетный методом НаборЗаписей.Загрузить()?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

При работе с регистрами бухгалтерии в 1С, особенно при массовой загрузке данных, метод НаборЗаписей.Загрузить() является мощным и эффективным инструментом. Однако, на пути к его использованию могут возникать сложности, одной из которых является корректная подготовка данных субконто в запросе. Мы рассмотрим типичную проблему, с которой сталкиваются разработчики, и покажем, как ее эффективно решить.

Изначально, разработчики часто предпочитают поэлементное заполнение записей регистра в цикле, например, так:


НоваяЗапись = НаборЗаписей.Добавить();
// ... заполнение других полей ...
НоваяЗапись.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры] = СсылкаНаДоговор;
// ...

Этот подход работоспособен, но может быть неэффективным при больших объемах данных. Для оптимизации мы стремимся использовать метод НаборЗаписей.Загрузить(), который позволяет загружать данные сразу из выборки запроса. Однако, при переходе к этому методу, мы сталкиваемся с требованием правильного формирования колонок для субконто.

Суть проблемы: "Требуется колонка вида субконто!"

Когда мы пытаемся загрузить данные в регистр бухгалтерии, содержащие субконто, система 1С ожидает, что для каждого поля субконто (например, СубконтоДт1, СубконтоКт1) в выборке запроса будет присутствовать соответствующая колонка, указывающая его *вид*. Если такая колонка отсутствует или содержит данные неверного типа, мы получаем ошибку:

"Ошибка Требуется колонка вида субконто! (ВидСубконтоДт1)."

или

"В колонке вид субконто содержится значение неверного типа! (ВидСубконтоДт1)"

Эта ошибка возникает из-за того, что система ожидает увидеть в колонке, например, ВидСубконтоДт1, не просто значение субконто (например, ссылку на контрагента) или его тип (результат функции ТИПЗНАЧЕНИЯ()), а именно ссылку на элемент предопределенного плана видов характеристик ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные. Это элемент, который описывает, к какому типу относится данное субконто (например, "Контрагенты", "Договоры", "Номенклатура" и т.д.).

Распространенная ошибка заключается в попытке вывести в запросе тип значения самого субконто, например, так:

ТИПЗНАЧЕНИЯ(СубконтоДт1) КАК ВидСубконтоДт1

Такой подход не приведет к успеху, поскольку ТИПЗНАЧЕНИЯ() возвращает строку с именем типа (например, "СправочникСсылка.Контрагенты"), а не ссылку на элемент из ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные, который ожидает система.

Понимание структуры субконто в 1С

Прежде чем перейти к решению, нам важно вспомнить, как устроено субконто в 1С. Каждый счет в плане счетов может иметь до трех видов субконто. Эти виды определяются в табличной части ВидыСубконто самого плана счетов. Для каждого счета там указано, какое субконто идет под первым номером, какое под вторым и какое под третьим. Именно эти данные нам и нужно извлечь.

Правильное формирование запроса: Шаг за шагом

Для корректной загрузки данных с субконто через НаборЗаписей.Загрузить(), мы должны убедиться, что наша выборка запроса содержит следующие колонки для каждого субконто (пример для дебета):

  1. Колонку со значением самого субконто, например, СубконтоДт1.
  2. Колонку с видом этого субконто, например, ВидСубконтоДт1, содержащую ссылку на элемент ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.

Рассмотрим пошагово, как правильно сформировать запрос:

1. Получаем сами значения субконто

Значения субконто (например, ссылка на конкретного контрагента, договор) мы обычно извлекаем из того же источника, откуда берем другие данные для регистра (например, из другого регистра, документа или таблицы).


// ...
Хозрасчетный.СубконтоДт1 КАК СубконтоДт1,
Хозрасчетный.СубконтоКт1 КАК СубконтоКт1,
// ...

2. Получаем виды субконто из Плана счетов

Это ключевой шаг. Виды субконто для конкретного счета не хранятся напрямую в записях регистра. Они определяются в настройках счета в ПланСчетов.Хозрасчетный, в его табличной части ВидыСубконто. Нам нужно будет выполнить левое соединение с этой табличной частью для каждого субконто (по дебету и по кредиту, для каждого из трех видов).

Пример соединения для первого вида субконто по дебету:


ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт1
    ПО Рег.СчетДт = ВидыСубконтоДт1.Ссылка
    И ВидыСубконтоДт1.НомерСтроки = 1

Здесь ВидыСубконтоДт1.Ссылка – это ссылка на сам счет, а ВидыСубконтоДт1.НомерСтроки указывает порядковый номер субконто (1, 2 или 3). Колонка ВидыСубконтоДт1.ВидСубконто будет содержать нужную нам ссылку на элемент ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.

3. Использование функции ЕСТЬNULL

Не каждый счет имеет три субконто. Если для счета определено меньше субконто, чем три, соответствующие строки в табличной части ВидыСубконто будут отсутствовать для более высоких номеров. В этом случае, левое соединение вернет NULL для полей вида субконто. Для корректной работы метода Загрузить() и для того, чтобы избежать ошибок, мы должны подставить пустую ссылку ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПустаяСсылка() в таких случаях. Для этого используем функцию ЕСТЬNULL:

ЕСТЬNULL(ВидыСубконтоДт1.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт1

Параметр &ПустойВидСубконто будет установлен в коде 1С перед выполнением запроса:


Запрос.УстановитьПараметр("ПустойВидСубконто", ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПустаяСсылка());

4. Правильное именование колонок

Метод НаборЗаписей.Загрузить() ожидает строго определенные имена колонок в выборке. Для субконто это СубконтоДтX и ВидСубконтоДтX, где X – это номер субконто (1, 2 или 3). Аналогично для кредита: СубконтоКтX и ВидСубконтоКтX.

Пример запроса для загрузки субконто

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

Предположим, что мы хотим загрузить записи в регистр, основываясь на данных, которые уже где-то существуют или были предварительно сформированы. В запросе мы должны вывести все поля регистра, которые хотим заполнить, включая измерения, ресурсы и, конечно же, субконто и их виды. Мы используем псевдоним Рег для источника данных, который содержит наши базовые проводки.


ВЫБРАТЬ
    // Стандартные поля регистра бухгалтерии
    Рег.Период КАК Период,
    Рег.СчетДт КАК СчетДт,
    Рег.СчетКт КАК СчетКт,
    Рег.Сумма КАК Сумма,
    Рег.Валюта КАК Валюта,
    Рег.ВалютнаяСумма КАК ВалютнаяСумма,
    Рег.Количество КАК Количество,
    Рег.Организация КАК Организация,
    Рег.Регистратор КАК Регистратор,
    Рег.НомерСтроки КАК НомерСтроки,
    Рег.ВидДвижения КАК ВидДвижения,

    // Субконто по дебету и их виды
    Рег.СубконтоДт1 КАК СубконтоДт1,
    ЕСТЬNULL(ВидыСубконтоДт1.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт1,
    Рег.СубконтоДт2 КАК СубконтоДт2,
    ЕСТЬNULL(ВидыСубконтоДт2.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт2,
    Рег.СубконтоДт3 КАК СубконтоДт3,
    ЕСТЬNULL(ВидыСубконтоДт3.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт3,

    // Субконто по кредиту и их виды
    Рег.СубконтоКт1 КАК СубконтоКт1,
    ЕСТЬNULL(ВидыСубконтоКт1.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт1,
    Рег.СубконтоКт2 КАК СубконтоКт2,
    ЕСТЬNULL(ВидыСубконтоКт2.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт2,
    Рег.СубконтоКт3 КАК СубконтоКт3,
    ЕСТЬNULL(ВидыСубконтоКт3.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт3
ИЗ
    РегистрБухгалтерии.Хозрасчетный КАК Рег // Или ваш источник данных, например, временная таблица или ТЧ документа
    // Соединения для получения видов субконто по дебету
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт1
        ПО Рег.СчетДт = ВидыСубконтоДт1.Ссылка
        И ВидыСубконтоДт1.НомерСтроки = 1
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт2
        ПО Рег.СчетДт = ВидыСубконтоДт2.Ссылка
        И ВидыСубконтоДт2.НомерСтроки = 2
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт3
        ПО Рег.СчетДт = ВидыСубконтоДт3.Ссылка
        И ВидыСубконтоДт3.НомерСтроки = 3
    // Соединения для получения видов субконто по кредиту
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт1
        ПО Рег.СчетКт = ВидыСубконтоКт1.Ссылка
        И ВидыСубконтоКт1.НомерСтроки = 1
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт2
        ПО Рег.СчетКт = ВидыСубконтоКт2.Ссылка
        И ВидыСубконтоКт2.НомерСтроки = 2
    ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт3
        ПО Рег.СчетКт = ВидыСубконтоКт3.Ссылка
        И ВидыСубконтоКт3.НомерСтроки = 3
// ГДЕ Рег.Регистратор = &Регистратор // Пример условия отбора по регистратору

Перед выполнением этого запроса в коде 1С, не забудьте установить параметр &ПустойВидСубконто, а также любые другие параметры, используемые в условии ГДЕ:


Запрос = Новый Запрос;
Запрос.Текст = "ВАШ_ТЕКСТ_ЗАПРОСА_СВЕРХУ";
Запрос.УстановитьПараметр("ПустойВидСубконто", ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПустаяСсылка());
// Если у вас есть другие параметры, например, для отбора по регистратору:
// Запрос.УстановитьПараметр("Регистратор", ДокументОбъект.Ссылка);

Заключительные шаги при загрузке

После того как запрос правильно сформирован и выполнен, полученную выборку (обычно в виде ТаблицыЗначений, полученной через Выгрузить()) можно использовать для метода НаборЗаписей.Загрузить(). Это значительно упростит и ускорит процесс записи данных в регистр.


// Создаем набор записей для регистра
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();

// Устанавливаем отбор по регистратору (если требуется обновить/перезаписать записи документа)
// Если мы создаем новые записи, отбор по регистратору может быть не нужен,
// но если мы хотим заменить существующие проводки документа, он обязателен.
НаборЗаписей.Отбор.Регистратор.Установить(ДокументОбъект.Ссылка);

// Если необходимо прочитать существующие записи регистратора для последующего изменения,
// а не полной перезаписи, то выполняем:
// НаборЗаписей.Прочитать();

// Создаем и выполняем запрос
Запрос = Новый Запрос;
Запрос.Текст = "
    ВЫБРАТЬ
        Рег.Период,
        Рег.СчетДт,
        Рег.СчетКт,
        Рег.Сумма,
        Рег.Валюта,
        Рег.ВалютнаяСумма,
        Рег.Количество,
        Рег.Организация,
        Рег.Регистратор,
        Рег.НомерСтроки,
        Рег.ВидДвижения,
        Рег.СубконтоДт1,
        ЕСТЬNULL(ВидыСубконтоДт1.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт1,
        Рег.СубконтоДт2,
        ЕСТЬNULL(ВидыСубконтоДт2.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт2,
        Рег.СубконтоДт3,
        ЕСТЬNULL(ВидыСубконтоДт3.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоДт3,
        Рег.СубконтоКт1,
        ЕСТЬNULL(ВидыСубконтоКт1.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт1,
        Рег.СубконтоКт2,
        ЕСТЬNULL(ВидыСубконтоКт2.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт2,
        Рег.СубконтоКт3,
        ЕСТЬNULL(ВидыСубконтоКт3.ВидСубконто, &ПустойВидСубконто) КАК ВидСубконтоКт3
    ИЗ
        РегистрБухгалтерии.Хозрасчетный КАК Рег
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт1
            ПО Рег.СчетДт = ВидыСубконтоДт1.Ссылка
            И ВидыСубконтоДт1.НомерСтроки = 1
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт2
            ПО Рег.СчетДт = ВидыСубконтоДт2.Ссылка
            И ВидыСубконтоДт2.НомерСтроки = 2
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоДт3
            ПО Рег.СчетДт = ВидыСубконтоДт3.Ссылка
            И ВидыСубконтоДт3.НомерСтроки = 3
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт1
            ПО Рег.СчетКт = ВидыСубконтоКт1.Ссылка
            И ВидыСубконтоКт1.НомерСтроки = 1
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт2
            ПО Рег.СчетКт = ВидыСубконтоКт2.Ссылка
            И ВидыСубконтоКт2.НомерСтроки = 2
        ЛЕВОЕ СОЕДИНЕНИЕ ПланСчетов.Хозрасчетный.ВидыСубконто КАК ВидыСубконтоКт3
            ПО Рег.СчетКт = ВидыСубконтоКт3.Ссылка
            И ВидыСубконтоКт3.НомерСтроки = 3
    ГДЕ
        Рег.Регистратор = &Регистратор"; // Отбираем записи по текущему регистратору

Запрос.УстановитьПараметр("ПустойВидСубконто", ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПустаяСсылка());
Запрос.УстановитьПараметр("Регистратор", ДокументОбъект.Ссылка);

ВыборкаИзЗапроса = Запрос.Выполнить().Выгрузить();

// Загружаем полученные данные в набор записей
НаборЗаписей.Загрузить(ВыборкаИзЗапроса);

// Записываем набор записей в регистр
НаборЗаписей.Записать();

Помните, что при использовании НаборЗаписей.Загрузить(), если записи с таким регистратором уже существуют и установлен отбор по регистратору, старые записи будут удалены и заменены новыми из выборки. Если отбор по регистратору не установлен, а записи с ключом уникальности (если он есть) совпадают, то поведение будет зависеть от настроек регистра.

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

← На главную