Как найти номенклатуру, которая не использовалась в документах в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Метод 1: Использование штатного запроса и Списка Значений

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

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

Рассмотрим пример кода для сбора данных:


// Создаем список для хранения найденных товаров
СписокИспользованныхТоваров = СоздатьОбъект("СписокЗначений");

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

Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        // Добавляем только конкретные элементы номенклатуры
        СписокИспользованныхТоваров.ДобавитьЗначение(Запрос.Товар);
    КонецЦикла;
КонецЕсли;

После того как мы получили СписокИспользованныхТоваров, перейдем ко второму этапу — получению списка всей номенклатуры (или выбранной группы), из которой нужно исключить найденные позиции. Разберем, как применить условие отрицания в новом запросе:


ТекстЗапросаОстатки = "
|Товар = Справочник.Номенклатура.ТекущийЭлемент;
|Группировка Товар без групп;
|Условие (НЕ(Товар В СписокИспользованныхТоваров));
|Условие (Товар.ЭтоГруппа = 0);
|";
// Если пользователь выбрал конкретную группу на форме, добавим условие вхождения
Если ВыбГруппа.Выбран() = 1 Тогда
    ТекстЗапросаОстатки = ТекстЗапросаОстатки + "Условие (Товар В ВыбГруппа);";
КонецЕсли;

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

Метод 2: Оптимизация через Таблицу Значений

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

Алгоритм действий будет следующим:

  1. Выгружаем всю номенклатуру из целевой группы в первую таблицу значений (ТЗ1).
  2. Выгружаем всю номенклатуру из документов во вторую таблицу значений (ТЗ2).
  3. Для ТЗ2 применяем метод Свернуть, чтобы остались только уникальные идентификаторы товаров.
  4. Перебираем ТЗ1 и для каждой строки проверяем наличие товара в ТЗ2 с помощью метода НайтиЗначение. Если значение найдено — удаляем строку из ТЗ1.

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


// 1. Получаем всю номенклатуру
ТЗ_Все = СоздатьОбъект("ТаблицаЗначений");
СпрН = СоздатьОбъект("Справочник.Номенклатура");
СпрН.ИспользоватьРодителя(ВыбГруппа);
СпрН.ВыбратьЭлементы();
Пока СпрН.ПолучитьЭлемент() = 1 Цикл
    Если СпрН.ЭтоГруппа = 1 Тогда Продолжить; КонецЕсли;
    ТЗ_Все.НоваяСтрока();
    ТЗ_Все.Товар = СпрН.ТекущийЭлемент();
КонецЦикла;

// 2. Получаем использованную номенклатуру (из запроса первого метода)
// Предположим, ТЗ_Использовано уже заполнена и свернута.
// 3. Фильтруем
Кол = ТЗ_Все.КоличествоСтрок();
Пока Кол > 0 Цикл
    ТЗ_Все.ПолучитьСтрокуПоНомеру(Кол);
    Если ТЗ_Использовано.НайтиЗначение(ТЗ_Все.Товар, , "Товар") > 0 Тогда
        ТЗ_Все.УдалитьСтроку(Кол);
    КонецЕсли;
    Кол = Кол - 1;
КонецЦикла;

Этот метод работает быстрее на файловых базах за счет того, что НайтиЗначение в оперативной памяти выполняется мгновенно по сравнению с тяжелыми SQL-подобными фильтрами в штатном движке запросов 7.7.

Метод 3: Прямая работа с DBF (для файловых версий)

Рассмотрим более продвинутый уровень, упомянутый опытными разработчиками. В файловой версии 1С 7.7 данные хранятся в формате DBF. Если нам нужно обработать колоссальный объем документов, штатный объект Документ или Запрос накладными расходами на создание объектов может замедлить процесс. Мы можем обратиться к файлу табличной части напрямую.

Посмотрим на последовательность действий:

  1. Открываем файл 1cv7.dd в корне каталога базы данных.
  2. Находим описание нашего документа. Ищем таблицу строк документа (обычно это файл вида DT[номер].dbf).
  3. Определяем имя поля, в котором хранится товар (например, SP123).
  4. Используем объект XBase для быстрого перебора этого файла и сбора ID товаров.

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

Метод 4: Использование SQL-запросов (1С++ и Direct SQL)

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

Вместо перебора данных в 1С, мы просим SQL Server вернуть нам разницу между двумя наборами данных, используя оператор EXCEPT или конструкцию NOT IN (или NOT EXISTS).


// Пример логики SQL запроса (упрощенно)
ТекстЗапроса = "
|SELECT id as [Товар $Справочник.Номенклатура]
|FROM $Справочник.Номенклатура
|WHERE isfolder = 0
|EXCEPT
|SELECT $ДокС.Товар
|FROM $ДокументСтроки.Реализация as ДокС
|";

Использование прямого SQL-запроса — это «золотой стандарт» для крупных систем на базе 7.7. Весь расчет происходит на сервере, и в 1С возвращается уже готовый, отфильтрованный список номенклатуры.

Важные рекомендации при реализации

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

  1. Пометка на удаление: По умолчанию запросы 1С 7.7 могут включать данные из помеченных на удаление документов. Если бизнес-логика требует учитывать только проведенные документы, обязательно добавьте фильтр Условие(Запрос.Документ.Проведен() = 1).
  2. Иерархия справочника: Помните, что в документах обычно выбираются элементы, а не группы. Если вы фильтруете номенклатуру, убедитесь, что вы сравниваете именно конечные элементы. Используйте ЭтоГруппа = 0 или проверку на уровень иерархии.
  3. Типы данных: В 1С 7.7 важно следить за типами. Если в табличной части документа реквизит «Товар» имеет неопределенный тип, в запросе нужно явно указывать вид: Товар = Документ.Реализация.Товар.Библиотека.Номенклатура.

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

← На главную