Как заполнить ГУИД в одной таблице 1С данными из другой таблицы по совпадению номенклатуры?

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

При работе в системе 1С:Предприятие 8.3 часто возникает задача, когда необходимо перенести данные из одной таблицы в другую на основе определенных условий. В нашем случае, мы рассмотрим ситуацию, когда требуется заполнить ГУИД (глобальный уникальный идентификатор) в первой таблице, основываясь на соответствии номенклатуры из второй таблицы. Это классическая задача, с которой сталкиваются как начинающие, так и опытные разработчики. Мы разберем два основных подхода к решению этой проблемы: с помощью перебора строк в цикле и использования запроса с левым соединением.

Представим, что у нас есть две таблицы. Первая таблица (назовем её условно Таблица1) содержит информацию о номенклатуре товара, его имени, количестве и пустом поле для ГУИДа. Вторая таблица (Таблица2) содержит номенклатуру поставщика и соответствующий ей ГУИД. Наша цель – заполнить поле ГУИД в Таблица1, если номенклатура из Таблица1 совпадает с номенклатурой поставщика из Таблица2. Важно, чтобы ГУИД проставлялся не случайным образом, а строго соответствовал найденной номенклатуре.

Метод 1: Перебор строк в цикле с использованием методов "Найти()" или "НайтиСтроки()"

Этот подход является наиболее интуитивным и простым для понимания, особенно для тех, кто только начинает осваивать программирование на 1С. Мы будем итерироваться по каждой строке первой таблицы и для каждой строки выполнять поиск соответствующего значения во второй таблице. Этот метод подходит для относительно небольших объемов данных, где производительность поиска не является критически важным фактором.

Использование метода "Найти()"

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

  1. Перебираем строки первой таблицы: Мы используем цикл Для Каждого СтрокаТЗ Из Таблица.Строки Цикл для прохода по каждой строке нашей Таблица1.
  2. Ищем соответствие во второй таблице: Внутри цикла для каждой строки из Таблица1 мы вызываем метод Найти() для Таблица2. Параметры метода: первое – значение, которое мы ищем (номенклатура из Таблица1), второе – имя колонки, в которой осуществляется поиск ("НоменклатураПоставщика" в Таблица2).
  3. Проверяем результат поиска: Метод Найти() возвращает найденную строку таблицы значений или Неопределено, если совпадение не найдено. Критически важно проверять результат на Неопределено, чтобы избежать ошибок при попытке обращения к несуществующей строке.
  4. Присваиваем ГУИД: Если строка найдена, мы присваиваем значение ГУИД из найденной строки Таблица2 соответствующему полю ГУИД в текущей строке Таблица1.

Давайте посмотрим на пример кода для этого метода:


// Предполагаем, что ВашаПерваяТаблица и ВашаВтораяТаблица - это объекты типа ТаблицаЗначений,
// в которых хранятся данные.

// ВашаПерваяТаблица имеет колонки: "Номенклатура", "ИмяТовара", "Количество", "ГУИД"
// ВашаВтораяТаблица имеет колонки: "НоменклатураПоставщика", "ГУИД"

Для Каждого СтрокаТаблицы1 Из ВашаПерваяТаблица Цикл
    // Ищем строку во второй таблице по Номенклатуре поставщика
    НайденнаяСтрокаТаблицы2 = ВашаВтораяТаблица.Найти(СтрокаТаблицы1.Номенклатура, "НоменклатураПоставщика");

    Если НайденнаяСтрокаТаблицы2 <> Неопределено Тогда
        // Если совпадение найдено, присваиваем ГУИД из второй таблицы
        СтрокаТаблицы1.ГУИД = НайденнаяСтрокаТаблицы2.ГУИД;
    Иначе
        // Обработка случая, когда совпадений не найдено.
        // Например, можно оставить ГУИД пустым, присвоить специальное значение,
        // или выдать сообщение пользователю.
        СтрокаТаблицы1.ГУИД = Неопределено; // или Новый УникальныйИдентификатор();
    КонецЕсли;
КонецЦикла;

Использование метода "НайтиСтроки()"

Метод НайтиСтроки() является более гибким по сравнению с Найти(), так как он позволяет найти все строки, удовлетворяющие заданным условиям, а не только первое совпадение. Это особенно полезно, если во второй таблице может быть несколько строк с одной и той же "Номенклатурой поставщика", и вам нужно обработать все эти совпадения (например, взять ГУИД из первой найденной строки, или принять более сложное решение о том, какой ГУИД использовать).

  1. Перебираем строки первой таблицы: Аналогично предыдущему методу, используем цикл Для Каждого СтрокаТЗ Из Таблица.Строки Цикл.
  2. Задаем параметры отбора: Для метода НайтиСтроки() мы создаем объект Новый Структура. В эту структуру мы добавляем пары "ключ-значение", где ключ – это имя колонки, по которой будет производиться отбор ("НоменклатураПоставщика"), а значение – искомое значение (номенклатура из текущей строки Таблица1).
  3. Выполняем поиск: Вызываем метод НайтиСтроки() для Таблица2, передавая ему нашу структуру параметров отбора. Метод вернет Массив найденных строк.
  4. Обрабатываем результат: Проверяем количество элементов в полученном массиве. Если массив не пустой (т.е. МассивНайденныхСтрокТаблицы2.Количество() > 0), это означает, что совпадения найдены. Мы можем взять ГУИД из первой найденной строки (МассивНайденныхСтрокТаблицы2[0].ГУИД) или реализовать более сложную логику, если возможно несколько ГУИДов для одной номенклатуры.

Рассмотрим пример использования НайтиСтроки():


// Предполагаем, что ВашаПерваяТаблица и ВашаВтораяТаблица - это объекты типа ТаблицаЗначений.

// ВашаПерваяТаблица имеет колонки: "Номенклатура", "ИмяТовара", "Количество", "ГУИД"
// ВашаВтораяТаблица имеет колонки: "НоменклатураПоставщика", "ГУИД"

Для Каждого СтрокаТаблицы1 Из ВашаПерваяТаблица Цикл
    // Задаем параметры отбора для поиска во второй таблице
    ПараметрыОтбора = Новый Структура("НоменклатураПоставщика", СтрокаТаблицы1.Номенклатура);

    // Ищем все строки во второй таблице, соответствующие нашей номенклатуре
    МассивНайденныхСтрокТаблицы2 = ВашаВтораяТаблица.НайтиСтроки(ПараметрыОтбора);

    Если МассивНайденныхСтрокТаблицы2.Количество() > 0 Тогда
        // Если найдено хотя бы одно совпадение, берем ГУИД из первой найденной строки.
        // Здесь можно реализовать более сложную логику, если найдено несколько ГУИДов.
        СтрокаТаблицы1.ГУИД = МассивНайденныхСтрокТаблицы2[0].ГУИД;
    Иначе
        // Обработка случая, когда совпадений не найдено.
        СтрокаТаблицы1.ГУИД = Неопределено;
    КонецЕсли;
КонецЦикла;

Важный момент: в сообщении 13 автор допустил ошибку, пытаясь использовать ТаблицаМатрица.Вставить(ПараметрыОтбора). Метод Вставить() используется для добавления новых строк в таблицу, а не для поиска. Правильным направлением, как было указано в сообщении 14, является использование НайтиСтроки().

Метод 2: Запрос с "ЛЕВОЕ СОЕДИНЕНИЕ"

Для работы с большими объемами данных метод перебора строк и поиска в цикле может быть не самым производительным. В таких случаях мы настоятельно рекомендуем использовать язык запросов 1С с оператором ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). Запросы в 1С оптимизированы для работы с данными и могут значительно ускорить выполнение операции.

Принцип работы ЛЕВОЕ СОЕДИНЕНИЕ заключается в следующем: мы выбираем все строки из "левой" (первой) таблицы и соответствующие им строки из "правой" (второй) таблицы. Если для строки из левой таблицы нет совпадений в правой, то поля из правой таблицы будут заполнены значением NULL (или Неопределено в терминах 1С). Это идеально подходит для нашей задачи, так как нам нужны все строки из первой таблицы, и для них нужно "подтянуть" ГУИД из второй, если он существует.

Реализация этого метода включает два основных шага:

  1. Формирование и выполнение запроса: Мы создаем объект Новый Запрос, пишем текст запроса на языке запросов 1С, устанавливаем параметры (передавая наши таблицы в запрос), выполняем запрос и выгружаем его результат.
  2. Обновление исходной таблицы по результатам запроса: Поскольку запрос возвращает новую таблицу со всеми необходимыми данными, нам нужно будет пройти по строкам исходной Таблица1 и обновить в ней ГУИДы, сверяясь с результатами запроса.

Шаг 1: Формирование и выполнение запроса

Мы сформируем запрос, который соединит Таблица1 и Таблица2 по условию совпадения номенклатуры. В запросе мы явно укажем, какие поля нам нужны из каждой таблицы.


// Создаем новый объект Запрос
Запрос = Новый Запрос;

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

// Устанавливаем параметры запроса. Важно, чтобы имена параметров (напр., "&Таблица1")
// совпадали с теми, что указаны в тексте запроса.
// Предполагаем, что ВашаПерваяТаблица и ВашаВтораяТаблица - это объекты типа ТаблицаЗначений,
// которые содержат исходные данные.
Запрос.УстановитьПараметр("Таблица1", ВашаПерваяТаблица);
Запрос.УстановитьПараметр("Таблица2", ВашаВтораяТаблица);

// Выполняем запрос и выгружаем результат в новую ТаблицуЗначений
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

После выполнения этого кода мы получим объект РезультатЗапроса, который является ТаблицейЗначений. Эта таблица будет содержать все поля, которые мы выбрали в запросе. Для каждой строки из ВашаПерваяТаблица в ней будет соответствующая строка, а поле ГУИДИзТаблицы2 будет содержать нужный ГУИД (или Неопределено, если совпадение не найдено).

Шаг 2: Обновление исходной таблицы по результатам запроса

Теперь, когда у нас есть все необходимые данные в РезультатЗапроса, нам нужно обновить поле ГУИД в нашей исходной ВашаПерваяТаблица. Мы не можем напрямую изменять ВашаПерваяТаблица в запросе, поэтому мы пройдем по ней циклом и будем брать значения из РезультатЗапроса.


// Перебираем строки исходной ВашаПерваяТаблица, чтобы обновить в ней ГУИДы
Для Каждого СтрокаТ1 Из ВашаПерваяТаблица Цикл
    // Используем структуру для поиска в РезультатЗапроса по номенклатуре.
    // Важно использовать имя колонки, как оно было названо в запросе (НоменклатураТ1).
    ПараметрыПоиска = Новый Структура("НоменклатураТ1", СтрокаТ1.Номенклатура);

    // Ищем соответствующие строки в РезультатЗапроса
    // Мы используем НайтиСтроки(), потому что в РезультатЗапроса
    // может быть несколько строк для одной номенклатуры из Таблицы1,
    // если в Таблице2 было несколько НоменклатурПоставщика с одним и тем же значением.
    НайденныеСтрокиРезультата = РезультатЗапроса.НайтиСтроки(ПараметрыПоиска);

    Если НайденныеСтрокиРезультата.Количество() > 0 Тогда
        // Если найдено хотя бы одно совпадение, берем ГУИД из первой найденной строки
        // результата запроса.
        // Здесь также можно реализовать более сложную логику, если в Таблице2
        // были дубликаты НоменклатурыПоставщика с разными ГУИДами.
        Если НайденныеСтрокиРезультата[0].ГУИДИзТаблицы2 <> Неопределено Тогда
            СтрокаТ1.ГУИД = НайденныеСтрокиРезультата[0].ГУИДИзТаблицы2;
        Иначе
            СтрокаТ1.ГУИД = Неопределено;
        КонецЕсли;
    Иначе
        // Если для данной номенклатуры из ВашаПерваяТаблица не найдено совпадений
        // в ВашаВтораяТаблица (что маловероятно после ЛЕВОГО СОЕДИНЕНИЯ,
        // но на всякий случай), то ГУИД остается Неопределено.
        СтрокаТ1.ГУИД = Неопределено;
    КонецЕсли;
КонецЦикла;

В этом коде мы вновь используем цикл по ВашаПерваяТаблица, а затем для каждой её строки ищем соответствующую строку в РезультатЗапроса, чтобы получить нужный ГУИД. Обратите внимание, что условие НайденныеСтрокиРезультата[0].ГУИДИзТаблицы2 <> Неопределено важно, так как при ЛЕВОМ СОЕДИНЕНИИ, если совпадений в правой таблице не было, соответствующее поле будет Неопределено.

Дополнительные рекомендации и особенности ГУИД

  1. Производительность:
    • Для небольших таблиц (до нескольких сотен или тысяч строк) оба метода (цикл + поиск и запрос) могут работать приемлемо по скорости.
    • Для больших объемов данных (десятки тысяч строк и более) метод с запросом (ЛЕВОЕ СОЕДИНЕНИЕ) будет значительно быстрее и предпочтительнее.
  2. Обработка отсутствия совпадений: Всегда предусматривайте обработку случаев, когда совпадений не найдено. В наших примерах мы присваиваем Неопределено, но вы можете выбрать другое поведение: выдать сообщение об ошибке, занести номенклатуру в список для ручной обработки или оставить поле пустым.
  3. Множественные совпадения: Если во второй таблице может быть несколько строк с одной и той же "Номенклатурой поставщика" и разными ГУИДами, вам нужно решить, какой ГУИД выбрать. В примерах мы брали первый найденный ГУИД (МассивНайденныхСтрок[0].ГУИД). В реальной ситуации может потребоваться более сложная логика, например, выбор ГУИД с определенным свойством или сообщение об ошибке, если ГУИДы неоднозначны.
  4. ГУИД (УникальныйИдентификатор): Глобальный уникальный идентификатор (GUID или в 1С УникальныйИдентификатор) используется для уникальной идентификации объектов в базе данных. Он формируется таким образом, что вероятность его совпадения с другим ГУИДом крайне мала. Если вам нужно получить УникальныйИдентификатор ссылки на объект, используйте метод УникальныйИдентификатор() у самой ссылки (например, СсылкаНаОбъект.УникальныйИдентификатор()). В нашем случае, мы просто переносим уже существующий ГУИД.

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

← На главную