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

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При переходе с платформы 1С 8.х на 1С 7.7 разработчики часто сталкиваются с отличиями в языке запросов. В платформе 8.х задача получения уникального списка номенклатуры из табличной части документа решается одной конструкцией ВЫБРАТЬ РАЗЛИЧНЫЕ. В платформе 1С 7.7 синтаксис запросов устроен иначе, поэтому аналогичную выборку можно реализовать несколькими способами.

Рассмотрим подробно все варианты решения этой задачи в конфигурации «Торговля и Склад 9.2» (или 9.3) на платформах 7.7: от штатного механизма запросов до использования оборотных регистров и прямых SQL-запросов.

Вариант 1. Штатный запрос к документам с группировкой

Разберем, как получить уникальный список позиций номенклатуры без повторов с помощью встроенного языка запросов 1С 7.7. Для исключения дублирования элементов достаточно применить секцию Группировка. Механизм группировки в 7.7 автоматически свёртывает совпадающие значения по аналогии с Сгруппировать По или ВЫБРАТЬ РАЗЛИЧНЫЕ.

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


ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|Обрабатывать Документы Проведенные;
|Номенклатура = Документ.ПоступлениеТоваров.Номенклатура;
|Группировка Номенклатура Без Групп;
|";

Проанализируем ключевые моменты этого запроса:

  1. Конструкция Группировка Номенклатура отсекает повторяющиеся позиции товаров, формируя список уникальных элементов.
  2. Модификатор Без Групп крайне важен: по умолчанию платформа 1С 7.7 добавляет в результаты запроса иерархические шапки (папки номенклатуры). Указание Без Групп гарантирует получение только конечных элементов справочника.
  3. Директива Обрабатывать Документы Проведенные; исключает попадание в результат номенклатуры из непроведенных или пометки на удаление документов.

Вариант 2. Запрос к регистру остатков или партий с фильтрацией по виду документа

Если требуется проанализировать фактически поступившие товары через движения регистров (например, ПартииНаличие или ОстаткиТМЦ), можно установить фильтр по типу документа-регистратора через выражение Условие.


ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Док = Регистр.ПартииНаличие.ТекущийДокумент;
|Группировка Номенклатура Без Групп;
|Условие(Док.Вид() = ""ПоступлениеТоваров"");
|";

Выясним техническую особенность этого подхода: условие Док.Вид() = "ПоступлениеТоваров" в штатных запросах 7.7 исполняется на стороне клиента (в памяти платформы), а не на уровне СУБД. Платформа сначала считывает все движения регистра за выбранный период, после чего фильтрует их по типу документа. На больших объёмах данных это может вызывать снижение производительности, однако на небольших базах работает вполне оперативно.

Вариант 3. Использование специализированного оборотного регистра Закупки

Чтобы избежать фильтрации по видам документов и отсечь прочие операции (такие как перемещения, списания или возвраты), в типовой конфигурации «Торговля и Склад» предпочтительно использовать оборотный регистр Закупки.

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


ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|Номенклатура = Регистр.Закупки.Номенклатура;
|Количество = Регистр.Закупки.Количество;
|Функция РассчитанноеКоличество = Приход(Количество);
|Группировка Номенклатура Без Групп;
|";

В этом случае функция Приход() автоматически отберет только те движения, которые отражают факт поступления ТМЦ от поставщиков, исключая необходимость писать дополнительные условия по типам документов.

Вариант 4. Прямой SQL-запрос (через 1С++ / ODBCRecordset)

Если база данных работает на Microsoft SQL Server и в проекте используется внешняя компонента 1С++, задачу можно решить прямым SQL-запросом. Это наиболее быстрый способ выборки данных большой базы.

Рассмотрим структуру SQL-запроса:


SELECT DISTINCT
    $Поступление.Номенклатура AS [Номенклатура $Справочник.Номенклатура]
FROM 
    $ДокументСтроки.ПоступлениеТМЦ AS Поступление
INNER JOIN 
    _1sjourn AS Жур ON Жур.iddoc = Поступление.iddoc
WHERE 
    Жур.iddocdef = $ВидДокумента.ПоступлениеТМЦ
    AND Жур.date_time_iddoc BETWEEN :НачДата AND :КонДата~
    AND Жур.ismark = 0
    AND (Жур.closed & 1 = 1)

Обратим внимание на критически важные условия при работе с таблицей журнала документов _1SJOURN:

  1. Жур.ismark = 0 — проверка того, что документ не помечен на удаление.
  2. (Жур.closed & 1 = 1) — проверка проведения документа. Без этого условия в итоговую выборку попадут данные из недействительных или распроведенных документов.

Вариант 5. Программный выбор через СписокЗначений

На небольших объемах документов выборка через программный цикл с заполнением объекта СписокЗначений может отрабатывать быстрее штатного объекта Запрос к табличным частям.


СписокТоваров = СоздатьОбъект("СписокЗначений");
Док = СоздатьОбъект("Документ.ПоступлениеТМЦ");

Док.ВыбратьДокументы(ДатаНач, ДатаКон);
Пока Док.ПолучитьДокумент() = 1 Цикл
    Если Док.Проведен() = 0 Тогда
        Продолжить;
    КонецЕсли;
    
    Док.ВыбратьСтроки();
    Пока Док.ПолучитьСтроку() = 1 Цикл
        Товар = Док.Номенклатура;
        Если СписокТоваров.Принадлежит(Товар) = 0 Тогда
            СписокТоваров.ДобавитьЗначение(Товар);
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Метод Принадлежит() проверяет наличие элемента в списке перед добавлением, что исключает дублирование записей без использования сторонних механизмов свёртывания.

← На главную