SQL-запрос с объединением агрегатов MAX () и SUM () - PullRequest
0 голосов
/ 02 октября 2018

Я пытался изучить различные темы здесь и на других форумах, но, похоже, я не могу найти решение своей проблемы.

Чего я пытаюсь добиться, так это "Показать чистые продажи (в долларах) линейки продуктов с самым высоким доходом для этого клиента. Используйте заголовок: «Лучшие продажи». Формат: $ 999 999,99.

Вот что я пробовал до сих пор:

SELECT cc.CustID, cc.CompanyName, cc.ContactName, pl.pl_id,to_char((sum(od.unitprice*od.quantity*(1-discount))), '$9,999,999.99') as rev
     FROM corp.customers cc JOIN corp.orders co ON (cc.CustID=co.CustID)
     LEFT OUTER JOIN corp.order_details od ON (co.orderID=od.orderID)
     LEFT OUTER JOIN corp.products cp ON (od.ProductID=cp.ProductID)
     LEFT OUTER JOIN corp.product_lines pl ON (cp.pl_id=pl.pl_id)
     GROUP BY cc.CustID, cc.CompanyName, cc.ContactName, pl.pl_id
     HAVING sum(od.unitprice*od.quantity*(1-discount))=
    ( 
       SELECT max(sum(od.unitprice*od.quantity*(1-discount)))
       FROM corp.customers cc JOIN corp.orders co ON (cc.CustID=co.CustID)
       JOIN corp.order_details od ON (co.orderID=od.orderID)
       JOIN corp.products cp ON (od.ProductID=cp.ProductID)
       JOIN corp.product_lines pl ON (cp.pl_id=pl.pl_id)
       GROUP BY cc.CustID, cc.CompanyName, cc.ContactName, pl.pl_id);

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

Результат показан ниже.

CustID  | Company Name  | Contact Name  | PL_ID | Revenue
QUICK   | QUICK-Stop    | Horst Kloss   | 1     | $37,161.63

Я бы хотел, чтобы это было похоже на

CustID  | Company Name  | Contact Name  | PL_ID | Revenue
QUICK   | QUICK-Stop    | Horst Kloss   | 1     | $37,161.63
QS      | QUICK-Start   | Clark Stone   | 2     | $50,000.00
QUI     | QUICK         | Mary Haynes   | 1     | $60,000.00
QShelf  | QUICK-Shelf   | Doreen Lucas  | 4     | $35,161.63

Любая помощь приветствуется. Спасибо!

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

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

WITH sample_data AS (SELECT 1 ID, 1 id2, 10 val FROM dual UNION ALL
                     SELECT 1 ID, 1 id2, 20 val FROM dual UNION ALL
                     SELECT 1 ID, 2 id2, 30 val FROM dual UNION ALL
                     SELECT 1 ID, 2 id2, 40 val FROM dual UNION ALL
                     SELECT 2 ID, 1 id2, 50 val FROM dual UNION ALL
                     SELECT 2 ID, 2 id2, 60 val FROM dual UNION ALL
                     SELECT 2 ID, 3 id2, 60 val FROM dual)
SELECT ID,
       id2,
       max_sum_val
FROM   (SELECT ID,
               id2,
               SUM(val) sum_val,
               MAX(SUM(val)) OVER (PARTITION BY ID) max_sum_val
        FROM   sample_data
        GROUP BY ID, id2)
WHERE  sum_val = max_sum_val;

        ID        ID2 MAX_SUM_VAL
---------- ---------- -----------
         1          2          70
         2          2          60
         2          3          60

Это отобразит все id2значения, которые имеют одинаковую сумму (val), которая является самой высокой.Если вы не хотите отображать все связанные строки, вместо этого вы можете использовать аналитическую функцию row_number():

WITH sample_data AS (SELECT 1 ID, 1 id2, 10 val FROM dual UNION ALL
                     SELECT 1 ID, 1 id2, 20 val FROM dual UNION ALL
                     SELECT 1 ID, 2 id2, 30 val FROM dual UNION ALL
                     SELECT 1 ID, 2 id2, 40 val FROM dual UNION ALL
                     SELECT 2 ID, 1 id2, 50 val FROM dual UNION ALL
                     SELECT 2 ID, 2 id2, 60 val FROM dual UNION ALL
                     SELECT 2 ID, 3 id2, 60 val FROM dual)
SELECT ID,
       id2,
       max_sum_val
FROM   (SELECT ID,
               id2,
               SUM(val) sum_val,
               row_number() OVER (PARTITION BY ID ORDER BY SUM(val) DESC, id2) rn
        FROM   sample_data
        GROUP BY ID, id2)
WHERE  rn = 1;

        ID        ID2 MAX_SUM_VAL
---------- ---------- -----------
         1          2          70
         2          2          60

ETA:

Это означает, что ваш запрос закончитсячто-то вроде:

SELECT custid,
       companyname,
       contactname,
       pl_id,
       to_char(rev, '$9,999,999.99') rev
FROM   (SELECT cc.custid,
               cc.companyname,
               cc.contactname,
               pl.pl_id,
               SUM(od.unitprice * od.quantity * (1 - discount)) AS rev,
               MAX(SUM(od.unitprice * od.quantity * (1 - discount))) OVER (PARTITION BY cc.custid) max_rev
        FROM   corp.customers cc
               INNER JOIN corp.orders co ON (cc.custid = co.custid)
               LEFT OUTER JOIN corp.order_details od ON (co.orderid = od.orderid)
               LEFT OUTER JOIN corp.products cp ON (od.productid = cp.productid)
               LEFT OUTER JOIN corp.product_lines PL ON (cp.pl_id = pl.pl_id)
        GROUP  BY cc.custid,
                  cc.companyname,
                  cc.contactname,
                  pl.pl_id)
WHERE  rev = max_rev;
0 голосов
/ 02 октября 2018

Этот запрос использует ваш исходный запрос, функцию rank () для упорядочения по вашему столбцу rev и выборку только для получения наибольшего оборота.Это даст несколько строк, если у вас есть несколько строк с одинаковым значением rev.Измените rank () на row_number (), если вам нужен только один.

Вы также можете использовать CTE вместо вложенных запросов, без разницы.

select CustID, CompanyName, ContactName, pl_id, rev from (
select CustID, CompanyName, ContactName, pl_id, to_char(rev, '$9,999,999.99') as rev,
    rank() over(order by rev desc) r
from (
    SELECT cc.CustID, cc.CompanyName, cc.ContactName, pl.pl_id,
        sum(od.unitprice*od.quantity*(1-discount)) as rev
    FROM corp.customers cc JOIN corp.orders co ON (cc.CustID=co.CustID)
    LEFT OUTER JOIN corp.order_details od ON (co.orderID=od.orderID)
    LEFT OUTER JOIN corp.products cp ON (od.ProductID=cp.ProductID)
    LEFT OUTER JOIN corp.product_lines pl ON (cp.pl_id=pl.pl_id)
    GROUP BY cc.CustID, cc.CompanyName, cc.ContactName, pl.pl_id
) q
) q2 where r=1
...