Как получить список непроданных товаров за период с помощью запроса в 1С

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

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

Методика определения непроданных товаров

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

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

Проанализируем структуру базового запроса, который позволяет увидеть движения товара:


ВЫБРАТЬ
    ОстаткиОстаткиИОбороты.Товар КАК Товар,
    ОстаткиОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
    ОстаткиОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток,
    ОстаткиОстаткиИОбороты.КоличествоПриход КАК Приход,
    ОстаткиОстаткиИОбороты.КоличествоРасход КАК Расход
ИЗ
    РегистрНакопления.Остатки.ОстаткиИОбороты(&ДатаНачала, &ДатаОкончания, , , ) КАК ОстаткиОстаткиИОбороты
ГДЕ
    ОстаткиОстаткиИОбороты.КоличествоРасход = 0

В данном примере мы обращаемся к виртуальной таблице ОстаткиИОбороты. Условие в секции ГДЕ отсекает все товары, по которым был зафиксирован расход. Однако стоит учитывать, что "Расход" в регистре остатков может означать не только продажу, но и списание или перемещение. Если ваша цель — именно продажи, стоит использовать регистр Продажи или анализировать поле Регистратор.

Работа с периодами и датами в запросе

Часто при тестировании запроса в консоли возникает желание "жестко" прописать даты прямо в тексте запроса, не используя таблицу параметров. Для этого в языке запросов 1С предусмотрена конструкция ДАТАВРЕМЯ. Рассмотрим подробнее, как ее использовать и какие ошибки допускают новички.

Синтаксис функции: ДАТАВРЕМЯ(Год, Месяц, День, Час, Минута, Секунда). Важно помнить:

  1. Существование даты: Нельзя указать несуществующую дату, например, 30 февраля. Это приведет к ошибке выполнения запроса.
  2. Лишние знаки: После последнего аргумента (секунд) перед закрывающей скобкой не должно быть запятой.
  3. Границы периода: Для получения корректных данных за день, дата окончания должна включать последнее мгновение суток (23:59:59).

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


ГДЕ
    Партия.Дата МЕЖДУ ДАТАВРЕМЯ(2022, 2, 1, 0, 0, 0) И ДАТАВРЕМЯ(2022, 2, 28, 23, 59, 59)

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

Решение через ЛЕВОЕ СОЕДИНЕНИЕ (продвинутый метод)

Иногда использование таблицы ОстаткиИОбороты с фильтром по расходу может быть недостаточно точным (например, если товар вообще не числился на складе в этом периоде, он не попадет в выборку). Выясним, как составить запрос, который найдет все товары из справочника Номенклатура, по которым не было продаж.

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Товар
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, , ) КАК ПродажиОбороты
ПО 
    Номенклатура.Ссылка = ПродажиОбороты.Номенклатура
ГДЕ
    Номенклатура.ЭтоГруппа = ЛОЖЬ
    И ПродажиОбороты.Номенклатура ЕСТЬ NULL

Разберем по шагам, как работает этот механизм:

  1. Мы берем все элементы из справочника Номенклатура.
  2. Присоединяем к ним данные о продажах за период. Используем именно ЛЕВОЕ СОЕДИНЕНИЕ, чтобы товары, которых нет в регистре продаж, не исчезли из итоговой таблицы.
  3. В условии ГДЕ мы проверяем поле ПродажиОбороты.Номенклатура ЕСТЬ NULL. Если продажи по товару были, это поле будет заполнено ссылкой. Если продаж не было — там будет NULL.
  4. Дополнительно фильтруем группы номенклатуры (ЭтоГруппа = ЛОЖЬ), чтобы в списке были только конечные товары.

Использование временных таблиц для оптимизации

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


// Помещаем проданные товары во временную таблицу
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Продажи.Номенклатура КАК Товар
ПОМЕСТИТЬ ПроданныеТовары
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Период МЕЖДУ &ДатаНачала И &ДатаОкончания
;

// Выбираем номенклатуру, которой нет во временной таблице
ВЫБРАТЬ
    Номенклатура.Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка НЕ В (ВЫБРАТЬ Товар ИЗ ПроданныеТовары)
    И НЕ Номенклатура.ЭтоГруппа

Этот метод позволяет платформе более эффективно использовать индексы. Обратите внимание на оператор НЕ В — он проверяет отсутствие ссылки в сформированном списке проданных товаров.

Заключение

Мы рассмотрели несколько способов получения списка непроданных товаров. Выбор конкретного метода зависит от вашей конфигурации:

← На главную