В практике программирования на платформе 1С часто возникают задачи, когда необходимо проанализировать поведение клиентов на основе специфических условий закупа. Например, нас могут интересовать не все продажи, а только те, где товар приобретался строго в количестве одной единицы за раз. При этом важно не просто найти такие продажи, но и ограничить итоговую выборку суммарным количеством этих "единичных" покупок за период. Рассмотрим подробно, как реализовать такую логику с помощью языка запросов 1С.
Для решения поставленной задачи нам необходимо выполнить три последовательных шага в рамках одного запроса:
Количество равно 1.Проанализируем пример кода, который решает эту задачу. Основная хитрость заключается в правильном использовании секций ГДЕ и ИМЕЮЩИЕ.
ВЫБРАТЬ
Продажи.Контрагент КАК Клиент,
Продажи.Номенклатура КАК Товар,
СУММА(Продажи.Количество) КАК ОбщееКоличество
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Количество = 1
И Продажи.Период МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
Продажи.Контрагент,
Продажи.Номенклатура
ИМЕЮЩИЕ
СУММА(Продажи.Количество) <= 50
В данном примере условие ГДЕ Продажи.Количество = 1 работает как первичный фильтр: система "выбрасывает" из обработки все строки, где за один раз было куплено 2, 3 или более единиц товара. Только после этого оставшиеся "единички" суммируются, и условие ИМЕЮЩИЕ проверяет, чтобы итоговый результат не превысил порог.
Рассмотрим ситуацию с точки зрения производительности системы. В приведенном выше примере мы обращаемся к основной таблице регистра (физической таблице). Это оправдано, так как нам нужно анализировать каждую конкретную запись на предмет равенства количества единице. Виртуальные таблицы (например, Обороты) здесь не подойдут, так как они выдают уже сгруппированные данные, и мы потеряем информацию о том, была ли это одна покупка на 10 единиц или 10 покупок по 1 единице.
Однако при работе с физическими таблицами важно помнить о следующих моментах:
Период, Номенклатура, Контрагент), проиндексированы. В типовых конфигурациях 1С измерения регистров индексируются автоматически.Регистратор.Состояние = &Состояние непосредственно в секции ГДЕ, если документов очень много. Это приводит к неявному соединению таблиц и замедляет запрос.Иногда под "покупкой в единственном числе" подразумевается не просто строка в документе, а весь чек целиком. То есть нас интересуют ситуации, когда клиент купил только одну единицу одного товара и больше ничего в этом документе нет. В этом случае простого условия Количество = 1 будет недостаточно.
Выясним, как решить такую задачу. Нам потребуется вложенный запрос или временная таблица, чтобы сначала определить список "чистых" документов (где всего 1 строка и количество в ней равно 1).
// Шаг 1: Отбираем регистраторы, где только одна строка и количество = 1
ВЫБРАТЬ
Продажи.Регистратор
ПОМЕСТИТЬ ВТ_ОдиночныеПродажи
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Регистратор
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Продажи.НомерСтроки) = 1
И СУММА(Продажи.Количество) = 1
;
// Шаг 2: Получаем итоговые данные по этим регистраторам
ВЫБРАТЬ
Продажи.Контрагент,
СУММА(Продажи.Количество) КАК Итого
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Регистратор В (ВЫБРАТЬ ВТ.Регистратор ИЗ ВТ_ОдиночныеПродажи КАК ВТ)
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
ИМЕЮЩИЕ
СУММА(Продажи.Количество) <= 50
Проанализируем ситуацию, когда в базе ведется учет в различных единицах измерения или по характеристикам. Если клиент купил "1 упаковку", в которой 20 банок пива, поле Количество в регистре может быть равно 1, если оно хранит данные в единицах отчетов, или 20, если в базовых единицах.
Важный совет: Всегда проверяйте, в каких единицах хранятся данные в вашем регистре. Если вы используете поле Количество, убедитесь, что это именно физические единицы (штуки/банки). Если учет ведется в упаковках, условие должно выглядеть так:
ГДЕ Продажи.Количество * Продажи.Коэффициент = 1
Если отчет строится за большой период и данных очень много, использование секции ИМЕЮЩИЕ на лету может быть медленным. Рассмотрим более профессиональный подход с использованием временных таблиц. Это позволит СУБД лучше оптимизировать план запроса.
ВЫБРАТЬ
Продажи.Контрагент КАК Клиент,
СУММА(Продажи.Количество) КАК СуммаЕдиничныхПокупок
ПОМЕСТИТЬ ВТ_Агрегация
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Количество = 1
И Продажи.Период МЕЖДУ &Начало И &Конец
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
;
ВЫБРАТЬ
ВТ.Клиент,
ВТ.СуммаЕдиничныхПокупок
ИЗ
ВТ_Агрегация КАК ВТ
ГДЕ
ВТ.СуммаЕдиничныхПокупок <= 50
Посмотрим, что мы сделали: сначала мы собрали все подходящие продажи во временную таблицу ВТ_Агрегация, просуммировали их, а затем вторым простым запросом отсекли лишнее. Такой подход считается эталонным при разработке сложных отчетов в 1С.
Подведем итог нашему исследованию. Для реализации условия "разовые покупки по 1 шт, суммарно не более 50" в 1С необходимо:
ГДЕ для фильтрации первичных строк (атомарных покупок).СГРУППИРОВАТЬ ПО для объединения данных по клиентам.ИМЕЮЩИЕ для наложения ограничения на результат агрегации.Используя эти методы, вы сможете гибко настраивать аналитические отчеты и выявлять специфические группы контрагентов, основываясь на их покупательских привычках.