Как выбрать максимальное значение после SUM () + Group By?

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

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

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

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

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

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


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

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

Edit: попытка исходного кода портирована из комментариев:

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 ответов


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;

есть много способов, чтобы кожа Этот кот... вот как я обычно это делаю:

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.


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

Так что у вас есть это:

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

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


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

   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

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