Как выбрать максимальное значение после SUM () + Group By? - PullRequest
6 голосов
/ 25 февраля 2012

У меня выпускной экзамен по SQL в колледже через несколько дней, и у меня есть вопрос, который сводит меня с ума! Я знаю, что это глупый запрос, но я только начинаю и не могу понять.

Итак, есть в основном 2 таблицы, Клиент и Заказы.

     Client           Orders
     ---------        ---------
 PK  Client_Id    PK  Order_Id
     Name             Client_Id   FK
                      Order_Total
                      Date

Теперь они просят меня «Указать имя клиента, который купил больше всего в 2011 году»

Итак, для того, что я думал, это требует, с одной стороны, чтобы я СУММИЛ все Order_Total и Group by Client с 2011 года, затем из этой таблицы выберите клиента с суммой MAX () сумм заказов, а затем показал только имя этого клиента. Проблема в том, что я не могу понять, как поместить все это в один запрос.

Надеюсь, кто-нибудь может помочь!


Спасибо всем за ваши очень быстрые ответы! Я действительно впечатлен!

Теперь я не хочу быть разборчивым или что-то в этом роде, но на всякий случай, если мой учитель не примет утверждение "Limit" или "Select top", есть ли способ выполнить этот запрос без них?

Редактировать: исходная попытка кода перенесена из комментариев:

SELECT 
  C.NAME
FROM 
  CLIENTS C,
  ORDERS O 
WHERE 
  O.CLIENT_ID = C.CLIENT_ID 
  AND O.DATE BETWEEN '1/1/2011 00:00:00.000' and '12/31/2011 23:59:59.999' 
HAVING SUM(O.ORDER_TOTAL) >= ALL (SELECT SUM (O2.ORDER_TOTAL) FROM ORDER O2 GROUP BY O2.CLIENT_ID)

Ответы [ 5 ]

4 голосов
/ 25 февраля 2012
SELECT T.X
 (SELECT C.NAME X, SUM(O.ORDER_TOTAL)
 FROM CLIENT C, ORDERS O
 WHERE C.CLIENT_ID = O.CLIENT_ID
   AND YEAR(O.DATE) = 2011
 GROUP BY O.CLIENT_ID
 ORDER BY 2 DESC
 LIMIT 1) T;
3 голосов
/ 25 февраля 2012

Есть много способов снять шкуру с этой кошки ... вот как я обычно это делаю:

select top 1 c.Client_Id, c.Name, o.Order_Total
from Client c
join (select Client_Id, SUM(Order_Total) as Order_Total
      from Orders 
      where `Date` between '1/1/2011 00:00:00.000' and '12/31/2011 23:59:59.999'
      group by Client_Id) o
  on c.Client_Id = o.Client_Id
order by o.Order_Total desc

По сути, вы вытягиваете итоговый список заказов, объединяетесь с ним, сортируете его по убыванию по сумме заказов и ограничиваете запрос до 1 результата.

1 голос
/ 13 ноября 2015
SELECT Client.Name
FROM Client LEFT JOIN Orders ON Orders.Client_Id = Client.Client_Id
WHERE YEAR(Orders.Date) = 2011
GROUP BY Client.Client_Id
ORDER BY SUM(Order.Order_Total) DESC
LIMIT 1
1 голос
/ 07 января 2013

Ответ Is7aq является правильным в соответствии с вашим вопросом, но будет работать только на MySQL.Также не учитывается возможность того, что больше чем один клиент купил больше всего за данный год, хотя я признаю, что это не было ограничением, перечисленным в первоначальном вопросе.Кроме того, это огромный удар по производительности для перекрестных объединений, просто используя запятые, когда ваши базы данных становятся достаточно большими, поэтому почти всегда лучше использовать INNER или OUTER объединения и указывать условие объединения.В любом случае, сделал это как упражнение, и вот что у меня было.Вероятно, это может быть лучше оптимизировано:

   CREATE TABLE #Client (
     Client_Id int not null,
     Name varchar(100) not null
   )

   INSERT INTO #Client VALUES (1, 'Client 1')
   INSERT INTO #Client VALUES (2, 'Client 2')
   INSERT INTO #Client VALUES (3, 'Client 3')

   CREATE TABLE #Orders (
     Order_Id int not null,
     Client_Id int not null,
     Order_Total int not null,
     Date datetime not null
   )

   -- Customer 1: total=105
   INSERT INTO #Orders VALUES (1, 1, 55, '1/1/2011')
   INSERT INTO #Orders VALUES (2, 1, 50, '1/1/2011')
   INSERT INTO #Orders VALUES (3, 1, 45, '1/1/2010') -- test removal of invalid dates

   -- Customer 2: total=120
   INSERT INTO #Orders VALUES (4, 2, 40, '1/1/2011')
   INSERT INTO #Orders VALUES (5, 2, 40, '1/1/2011')
   INSERT INTO #Orders VALUES (6, 2, 40, '1/1/2011')

   -- Customer 3: total=120
   INSERT INTO #Orders VALUES (7, 3, 40, '1/1/2011')
   INSERT INTO #Orders VALUES (8, 3, 40, '1/1/2011')
   INSERT INTO #Orders VALUES (9, 3, 40, '1/1/2011')

   -- control customer to test hi/lo scenarios: total=40
   INSERT INTO #Orders VALUES (10, 4, 10, '1/1/2011')
   INSERT INTO #Orders VALUES (11, 4, 10, '1/1/2011')
   INSERT INTO #Orders VALUES (12, 4, 10, '1/1/2011')
   INSERT INTO #Orders VALUES (13, 4, 10, '1/1/2011')

   SELECT T.NAME, 
          T.OrderTotal
     FROM (SELECT C.NAME, 
                  SUM(O.ORDER_TOTAL) OrderTotal
             FROM #CLIENT C
            INNER JOIN #ORDERS O
               ON c.CLIENT_ID = o.CLIENT_ID
            WHERE YEAR(O.DATE) = 2011
         GROUP BY C.NAME) as T
     WHERE T.OrderTotal = (SELECT MAX(T2.OrderTotal2)
                             FROM (SELECT C2.NAME, 
                                          SUM(O2.ORDER_TOTAL) OrderTotal2
                                     FROM #CLIENT C2
                               INNER JOIN #ORDERS O2
                                       ON c2.CLIENT_ID = o2.CLIENT_ID
                                    WHERE YEAR(O2.DATE) = 2011
                                 GROUP BY C2.NAME) as T2) 
  GROUP BY T.Name, T.OrderTotal

  DROP TABLE #Client
  DROP TABLE #Orders

  -- Output
  -- Client 2: 120
  -- Client 3: 120
1 голос
/ 25 февраля 2012

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

Итак, у вас есть это:

select c.client_id, c.name, sum(order_total) ordersum
from client c 
inner join orders o on c.client_id = o.client_id
where year(o.date) = 2011
group by c.client_id, c.name

Это дает вам ваши суммы. Теперь вы хотите первый. Есть несколько способов сделать это, и это также зависит от того, какую СУБД вы используете (mysql, mssql и т. Д.). Самый простой способ - это:

select top 1 *
from (
select c.client_id, c.name, sum(order_total) ordersum
from client c 
inner join orders o on c.client_id = o.client_id
where year(o.date) = 2011
group by c.client_id, c.name
) a
order by ordersum desc

Может быть что-то более простое на данной платформе, но этот запрос должен быть достаточно универсальным, чтобы работать на любой СУБД, которую вы используете.

...