Почему в запросе 1С появляются дублирующиеся записи при добавлении новой таблицы и как это исправить?

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

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

Анализ исходной проблемы: декартово произведение

Разберем ситуацию, описанную автором. Изначально запрос выбирает одну ссылку из справочника Номенклатура во временную таблицу по конкретному параметру. В этом случае результат предсказуем — 1 строка. Однако, как только в секцию ИЗ основного запроса добавляется таблица РегистрСведений.ШтрихкодыНоменклатуры через запятую, результат удваивается.

Проанализируем конструкцию секции ИЗ (FROM):


ИЗ
    ВременнаяТаблица КАК ВременнаяТаблица,
    РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры

Использование запятой между таблицами в языке запросов 1С (как и в классическом SQL) означает выполнение операции CROSS JOIN (перекрестное соединение) или создание декартова произведения. Выясним причину такого поведения: при перекрестном соединении система берет каждую запись из первой таблицы и сопоставляет ее с каждой записью из второй таблицы.

Представим это математически: если во ВременнаяТаблица содержится N записей, а в таблице ШтрихкодыНоменклатуры содержится M записей, то итоговый результат будет содержать N * M строк. В примере автора во временной таблице была 1 запись, а в регистре штрихкодов, судя по всему, нашлось 2 записи (неважно, относятся они к этой номенклатуре или нет, если условия связи отсутствуют). В итоге: 1 * 2 = 2 строки.

Важный момент: даже если вы не выбираете поля из второй таблицы в секции ВЫБРАТЬ, само ее присутствие в секции ИЗ через запятую заставляет СУБД перемножать строки. Выбор полей лишь скрывает значения из второй таблицы, но не удаляет лишние строки, которые она породила.

Разберем, как работает реляционная алгебра в запросах

Посмотрим на ситуацию глазами сервера базы данных. Процесс выполнения запроса идет в определенной последовательности:

  1. Сначала формируется набор данных в секции ИЗ. Здесь происходит соединение всех указанных таблиц. Если указана запятая — происходит полное перемножение.
  2. Затем накладываются условия из секции ГДЕ (в примере автора их нет для второй таблицы).
  3. В последнюю очередь отрабатывает секция ВЫБРАТЬ, которая просто «обрезает» лишние колонки, оставляя только нужные поля.

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

Как исправить запрос: использование соединений (JOIN)

Чтобы избежать неконтролируемого умножения строк, необходимо использовать явные соединения с указанием условия связи. Разберем самый правильный вариант — ЛЕВОЕ СОЕДИНЕНИЕ. Это позволит нам получить данные из основной таблицы (номенклатуры) и «подтянуть» к ним данные из регистра штрихкодов только там, где они действительно соответствуют нашей номенклатуре.

Рассмотрим исправленный пример кода:


ВЫБРАТЬ
    ВременнаяТаблица.Ссылка КАК Ссылка,
    ШтрихкодыНоменклатуры.Штрихкод КАК Штрихкод
ИЗ
    ВременнаяТаблица КАК ВременнаяТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры
        ПО ВременнаяТаблица.Ссылка = ШтрихкодыНоменклатуры.Номенклатура

В данном случае мы используем ключевое слово ПО, которое жестко ограничивает сопоставление строк. Теперь строка из временной таблицы соединится только с теми строками регистра, где поле Номенклатура совпадает со ссылкой. Если у товара нет штрихкода, строка останется одна, а поле штрихкода будет содержать NULL. Если у товара 2 штрихкода, строк по-прежнему будет две, но это уже будет логически обосновано наличием данных, а не ошибкой перемножения всех записей регистра.

Оптимизация работы с временными таблицами

Проанализируем первую часть запроса автора, где он помещает одну ссылку во временную таблицу. С точки зрения производительности и «лучших практик» 1С, это не всегда оправдано. Создание временной таблицы — это операция, требующая ресурсов (запись в TempDB на SQL-сервере).

Если вам нужно просто получить данные по одной номенклатуре, лучше использовать параметр напрямую, без создания промежуточных таблиц:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Штрихкоды.Штрихкод КАК Штрихкод
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        ПО Номенклатура.Ссылка = Штрихкоды.Номенклатура
ГДЕ
    Номенклатура.Ссылка = &Ссылка

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВременнаяТаблица
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка = &Ссылка

ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

Почему дублей может быть больше двух?

Выясним причину, по которой автор увидел именно две записи. В его тестовой базе в регистре ШтрихкодыНоменклатуры, вероятно, всего две записи вообще (для любых товаров). Если бы в базе было 10 000 штрихкодов, запрос выдал бы 10 000 одинаковых строк для одной номенклатуры. Это крайне опасная ситуация: на реальной базе данных такой запрос может привести к «падению» сервера из-за нехватки оперативной памяти или переполнения дискового пространства временными файлами базы данных.

Итоги и рекомендации

Подводя итог нашему разбору, выделим основные правила написания качественных запросов в 1С:

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

← На главную