Заметки по SQL: Создание аналога аналитической агрегатной функции, которая находит максимальное (минимальное) значение в пределах окна в группе простым запросом

04.05.26

Разработка - Запросы

В статье рассматривается создание аналога аналитической агрегатной функции, которая находит максимальное (минимальное) значение в пределах окна в группе с использованием простого SQL запроса.

Это вторая статья по аналитическим функциям. С первой статьёй можно познакомиться здесь - //infostart.ru/1c/articles/2238021/.

 

Постановка задачи.

Необходимо сравнить продажи менеджеров с значением продаж самого эффективного менеджера за месяц.

Исходные данные:

 

 

Результат на выходе:

 

         

 

 
Решение классическим SQL.
select emp.name,
       emp.val,
       emp.месяц,
       (select max(val) from employees where месяц = emp.месяц) max_val
from employees emp

 

Запрос не является оптимальным, поскольку в каждой строке запроса выполнятся дополнительный запрос ко всем данным в кадой строчке запроса. Кроме того, 1С не поддерживает подзапросы в разделе SELECT.

 

Использование аналитической функции:

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

 
 Основные характеристики
 
 Запрос для нашей задачи:
select emp.name,
       emp.val,
       emp.месяц,
       max(val) over (partition by месяц) max_val
from employees emp

1С не поддерживает аналитические функции, хотя на них в SQL сформировался свой стандарт.

 

Аналог аналитических функций в 1С

В 1С СКД есть свои аналитические функции: ВычислитьВыражение, ВычислитьВыражениеСГруппировкойМассив, ВычислитьВыражениеСГруппировкойТаблицаЗначений. Данные функции реализованы только в СКД и выполняются только после основного запроса. Фактически обработка данных производится на стороне сервера 1С, а не сервера баз данных.

Синтаксис функции «ВычислитьВыражениеСГруппировкойМассив»

ВычислитьВыражениеСГруппировкойМассив (Выражение, ВыраженияПолейГруппировки, ОтборЗаписей, ОтборГруппировок).

Параметры:

  • Выражение - выражение, которое нужно вычислить. Тип Строка. Например, "Сумма(СуммаОборот)"; 
  • ВыраженияПолейГруппировки - выражения полей группировки, перечисленные через запятую. Например, "Контрагент, Партия"; 
  • ОтборЗаписей - выражение, применяемое к детальным записям. Например, "ПометкаУдаления = Ложь". Если в данном параметре используется агрегатная функция, то при выполнении компоновки данных возникнет ошибка; 
  • ОтборГруппировок - отбор, применяемый к групповым записям. Например: "Сумма(СуммаОборот) > &Параметр1".

Как видим, синтаксис похож на синтаксис аналитической функции SQL.

Функция ВычислитьВыражениеСГруппировкойМассив позволят возвращать массив, каждый элемент которого содержит результат вычисления выражения для группировки по указанному полю. То есть массив вычисляемых полей.

 

 
 Предлагаемое решение:
 
 Запрос, формирующий набор данных для тестов:
 
 Сам запрос:
ВЫБРАТЬ
	ВременнаяТаблица.val КАК max_val,
	ВременнаяТаблица.name КАК max_name,
	ВременнаяТаблица2.val КАК val,
	ВременнаяТаблица2.name КАК name,
	ВременнаяТаблица2.Month КАК Month
ИЗ
	ВременнаяТаблица КАК ВременнаяТаблица2
		ЛЕВОЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица
			ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица1
			ПО ВременнаяТаблица.Month = ВременнаяТаблица1.Month
		ПО ВременнаяТаблица2.Month = ВременнаяТаблица.Month

СГРУППИРОВАТЬ ПО
	ВременнаяТаблица.name,
	ВременнаяТаблица.val,
	ВременнаяТаблица2.Month,
	ВременнаяТаблица2.val,
	ВременнаяТаблица2.name

ИМЕЮЩИЕ
	МАКСИМУМ(ВременнаяТаблица1.val) = ВременнаяТаблица.val

УПОРЯДОЧИТЬ ПО
	Month
 
 Анализ  запроса

 

ВЫБРАТЬ
	ВременнаяТаблица.val КАК val,
	ВременнаяТаблица.name КАК name,
	ВременнаяТаблица.Month КАК Month
ПОМЕСТИТЬ ВременнаяТаблица1
ИЗ
	ВременнаяТаблица КАК ВременнаяТаблица
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица1
		ПО ВременнаяТаблица.Month = ВременнаяТаблица1.Month

СГРУППИРОВАТЬ ПО
	ВременнаяТаблица.Month,
	ВременнаяТаблица.name,
	ВременнаяТаблица.val

ИМЕЮЩИЕ
	МАКСИМУМ(ВременнаяТаблица1.val) = ВременнаяТаблица.val

условие  ИМЕЮЩИЕ МАКСИМУМ(ВременнаяТаблица1.val) = ВременнаяТаблица. val

ищет максимальное значение val за месяц.

Если заменить это условие на ИМЕЮЩИЕ МИНИМУМ (ВременнаяТаблица1.val) = ВременнаяТаблица. val

то получим минимальное значение за месяц.

ЛЕВОЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица ПО ВременнаяТаблица.месяц = ВременнаяТаблица1.месяц

создаёт окно просмотра.

Такая конструкция позволяет не только получить максимальное значение val за месяц, но и сразу узнать какому сотруднику оно принадлежит. Для аналитической функции SQL необходимо будет использовать два выражния.

Усложним условие.

Предположим за третий месяц два сотрудника продали товара на одинаковую сумму, для этого добавим во временную таблицу, формирующую исходные данные, ещё одно объединение:

ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
	153,
	405,
	"Garii",
	"3",
	ДАТАВРЕМЯ(2026, 3, 4)

В результате выполнения запроса записи по Garii и Dgon будут удвоены. Чтобы исключить удвоение, добавим дополнительное условие с минимальной датой записи. Кто первый достиг максимума продаж тот и лучший.

ИМЕЮЩИЕ

            МАКСИМУМ(ВременнаяТаблица1.val) = ВременнаяТаблица.val И

            МИНИМУМ(ВременнаяТаблица2.Data_val) = ВременнаяТаблица.Data_val

В результате запрос принимает следующий вид:

ВЫБРАТЬ
	ВременнаяТаблица.val КАК max_val,
	ВременнаяТаблица.name КАК max_name,
	ВременнаяТаблица.Data_val КАК Data_val,
	ВременнаяТаблица.Month КАК Month,
	ВременнаяТаблица3.name КАК name,
	ВременнаяТаблица3.val
ИЗ
	ВременнаяТаблица КАК ВременнаяТаблица3
		ЛЕВОЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица1
		ПО (ВременнаяТаблица.Month = ВременнаяТаблица1.Month)
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица2
		ПО (ВременнаяТаблица.val = ВременнаяТаблица2.val)
	ПО (ВременнаяТаблица3.Month = ВременнаяТаблица.Month)

СГРУППИРОВАТЬ ПО
	ВременнаяТаблица.name,
	ВременнаяТаблица.val,
	ВременнаяТаблица.Data_val,
	ВременнаяТаблица.Month,
	ВременнаяТаблица3.val,
	ВременнаяТаблица3.name

ИМЕЮЩИЕ
	МАКСИМУМ(ВременнаяТаблица1.val) = ВременнаяТаблица.val И
	МИНИМУМ(ВременнаяТаблица2.Data_val) = ВременнаяТаблица.Data_val

УПОРЯДОЧИТЬ ПО
	Month,
Data_val1

Результат.

 

 

Фактически, мы получили аналог работы с классическим регистром сведений, где ресурсами являются месяц и сотрудник, а измерением сумма продаж.

 

                                               Примеры применения запроса.

  1. Сравнение производительности сотрудников (подразделений).
  2. Сравнение прибыли (расходов) по месяцам с прибылью максимально эффективного месяца.
  3. Вычисление максимального (минимального) стажа по специальностям.
  4. Определение контрагента с максимальной задолженностью.

 

Ссылки на другие статьи автора по теме запросов SQL на инфостарте.

Преобразование в запросе строки в дату одним  выражением - //infostart.ru/1c/articles/1567059/ .

Запрос, получающий изменения ресурса в регистрах сведений по датам изменения за период - //infostart.ru/1c/articles/1041396/

 Генерация ряда дат и данные из периодических регистров на каждый день - //infostart.ru/1c/articles/1012148/ .

Срез последних - аналог запроса - //infostart.ru/1c/articles/980323/.

 

 

 

 

Вступайте в нашу телеграмм-группу Инфостарт

запросы SQL аналитические функции

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    258818    1430    421    

1165

WEB-интеграция Запросы Программист 1С 8.3 Абонемент ($m)

Post1C - это внешняя обработка, которая превращает 1С в полноценный инструмент для тестирования REST API. Всё управление сосредоточено в одном окне: настройка запроса, выполнение, просмотр ответа и генерация кода - без переключения между формами. Аналог Postman, но работающий в привычной среде 1С.

1 стартмани

02.04.2026    2222    68    priem_nv    23    

65

Инструментарий разработчика Запросы Программист 1С 8.3 1С:Библиотека стандартных подсистем Абонемент ($m)

Представляю новую версию подсистемы работы со схемой запроса, которая завершает её эволюцию от библиотеки по работе со схемой запроса до объектной реализации модели запроса 2. Теперь есть выбор между классическим и текучим стилем написанию кода - оба варианта взаимозаменяемы. Ключевое улучшение - использование объектов в качестве источников данных, значений полей и параметров в условиях виртуальных таблиц, а также новые операторы позиционирования в схеме

1 стартмани

29.03.2026    1766    kalyaka    16    

23

Инструментарий разработчика Запросы Программист 1С:Предприятие 8 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    11237    147    zup_dev    30    

83

Инструментарий разработчика Запросы Программист 1С:Предприятие 8 1С:ERP Управление предприятием 2 Абонемент ($m)

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

2 стартмани

05.03.2025    6525    21    XilDen    12    

29

Обновление 1С Запросы Программист 1С:Предприятие 8 1С:ERP Управление предприятием 2 Абонемент ($m)

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

3 стартмани

06.02.2025    5787    36    XilDen    26    

42

Запросы Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

В статье приведена удобная возможность отладки исполняемого запроса динамического списка.

03.12.2024    13006    artemusII    11    

27
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. paulwist 04.05.26 11:55 Сейчас в теме
Запрос не является оптимальным, поскольку в каждой строке запроса выполнятся дополнительный запрос ко всем данным.


Хм, приведите, плиз, пример оптимального запроса возвращающий max_val и не выполняющий запроса ко всем данным. (можно на любом удобном диалекте SQL)
3. IVC_goal 240 04.05.26 12:45 Сейчас в теме
(1) Речь идет о дополнительных запросах в каждой полученной строке основного запроса. В предлагаемом варианте ко выполняется два индексированных запроса ко всем данным.
ВременнаяТаблица КАК ВременнаяТаблица
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица КАК ВременнаяТаблица1
ПО ВременнаяТаблица.Month = ВременнаяТаблица1.Month
4. paulwist 04.05.26 13:08 Сейчас в теме
Ну, не совсем это. Ладно.

Вопрос:

что вы подразумеваете под "два индексированных запроса ко всем данным" , поясните??

(3)
В предлагаемом варианте ко выполняется два индексированных запроса ко всем данным.
5. IVC_goal 240 04.05.26 15:28 Сейчас в теме
(4) ВременнаяТаблица содиняется сама с сбобой ВременнаяТаблица1 с автоматичским созданием индекса Month (ВременнаяТаблица.Month = ВременнаяТаблица1.Month)
7. paulwist 05.05.26 09:17 Сейчас в теме
(5)
ВременнаяТаблица содиняется сама с сбобой ВременнаяТаблица1 с автоматичским созданием индекса Month (ВременнаяТаблица.Month = ВременнаяТаблица1.Month)


Ну вот, вы сами получили "двойное" чтение таблички :)

Тогда почему,

select  emp.name,
       emp.val,
       emp.месяц,
       (select  max(val) from  employees where  месяц = emp.месяц) max_val
from  employees emp


Запрос не является оптимальным, поскольку в каждой строке запроса выполнятся дополнительный запрос ко всем данным в кадой строчке запроса.


если в вашем же решение используется тоже самое ?? :) :) :)
8. IVC_goal 240 05.05.26 14:21 Сейчас в теме
(7) Интерсно, есть разница 2 раза или 1+количство строк?
10. paulwist 08.05.26 09:05 Сейчас в теме
(8)
Интерсно, есть разница 2 раза или 1+количство строк?


Что бы ответить надо смотреть планы запросов, наличие индексов, актуальность статистики итд итп.
2. IVC_goal 240 04.05.26 12:29 Сейчас в теме
Если я правильно понял ваш ворос
6. Mdanko 05.05.26 09:00 Сейчас в теме
1. Путаница с именем поля Month/Месяц. То по английски, то по русски. Это чтобы никто не догадался?
2. Используйте CTE. В 1с это как раз временные таблицы.
with max_by_month as (select  "month", max(val) as max_val from  employees group by "month")
select  emp.name,
       emp.val,
       emp."month",
       mbm.max_val
from  employees emp left join max_by_month mbm on emp."month" = mbm."month"

3. В итоге обыкновенный group by и having. Так и не понял в чем суть статьи и где мы создали аналитические функции?
paulwist; +1 Ответить
9. IVC_goal 240 05.05.26 14:24 Сейчас в теме
(6)
2. С месяцем залёт, сначала был мес, затем ршил исправить на mont. Но видно не везде исправил.
Виноват, прошу сильно не бить
3. Показал стрелками где функция.
Прикрепленные файлы:
Для отправки сообщения требуется регистрация/авторизация