Нужен эффективный запрос на сумму и сумму - PullRequest
2 голосов
/ 28 июня 2019

У меня есть SQL-запрос, чтобы выбрать сумму сумм согласно сценарию ниже.

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

Ниже приводится SQL, который у меня есть. Это работает. Но ищем более эффективный способ реализации, учитывая 100 тыс. Записей в таблице.

SELECT 
D1.Manager_name,
D1.location_name,
sum(D1.sale_amount) sale_amount,
(select sum(D2.sale_amount) from details D2 where D1.Manager_name = D2.Manager_name) total_amount
FROM details D1
GROUP BY 
D1.Manager_name,
D1.location_name;

Данные таблицы и ожидаемые выходные данные

Ответы [ 2 ]

5 голосов
/ 28 июня 2019

Вы можете попробовать использовать SUM в качестве оконной функции, чтобы заменить коррелированный подзапрос:

SELECT 
    D1.Manager_name,
    D1.location_name,
    SUM(D1.sale_amount) sale_amount,
    SUM(SUM(D1.sale_amount)) OVER (PARTITION BY D1.Manager_name) total_amount
FROM details D1
GROUP BY 
    D1.Manager_name,
    D1.location_name;

Вот объяснение того, что происходит. Оконные функции всегда оцениваются last . Единственное, что выполняется после оконной функции - это предложение ORDER BY. В приведенном выше случае после оценки GROUP BY единственными столбцами, доступными в промежуточном результате, являются Manager_name, location_name и SUM(sale_amount). Когда мы используем SUM в качестве оконной функции с разделением по менеджерам, мы можем найти общую сумму для каждого менеджера во всех агрегированных местоположениях.

1 голос
/ 28 июня 2019

Если вы принимаете другой способ отображения данных, есть расширение предложения GROUP BY, которое даст вам как промежуточные итоги, так и итоги, которые вы хотите получить за один проход.Здесь я генерирую 99999 строк и получаю вывод за 0,03 секунды.

with m(manager_name) as (
  select 'Mgr '||level from dual connect by level <= 3
)
, l(location_name) as (
  select 'Location '||level from dual connect by level <= 3
)
, s(sale_amount) as (
  select level from dual connect by level <= 100000/9
)
select  
Manager_name,
location_name,
sum(sale_amount) sale_amount
FROM m, l, s
GROUP BY Manager_name,
rollup(location_name);

MANAGER_NAME LOCATION_NAME SALE_AMOUNT
------------ ------------- -----------
Mgr 1        Location 1       61732716
Mgr 1        Location 2       61732716
Mgr 1        Location 3       61732716
Mgr 1                        185198148
Mgr 2        Location 1       61732716
Mgr 2        Location 2       61732716
Mgr 2        Location 3       61732716
Mgr 2                        185198148
Mgr 3        Location 1       61732716
Mgr 3        Location 2       61732716
Mgr 3        Location 3       61732716
Mgr 3                        185198148
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...