The MAX function computes the maximum based on a group of values. For the examples that follow, please reference the orders table within the order entry (oe) schema at livesql.oracle.com. The contents of this table can also be found below. This table contains one row for each order placed by a customer.
| order_id | order_date | order_mode | customer_id | order_status | order_total | sales_rep_id | promotion_id |
|---|---|---|---|---|---|---|---|
| 2458 | 16-AUG-07 03.34.12.234359 PM | direct | 101 | 0 | 78279.6 | 153 | – |
| 2397 | 19-NOV-07 02.41.54.696211 PM | direct | 102 | 1 | 42283.2 | 154 | – |
| 2454 | 02-OCT-07 05.49.34.678340 PM | direct | 103 | 1 | 6653.4 | 154 | – |
| 2354 | 14-JUL-08 06.18.23.234567 PM | direct | 104 | 0 | 46257 | 155 | – |
| 2358 | 08-JAN-08 05.03.12.654278 PM | direct | 105 | 2 | 7826 | 155 | – |
| 2381 | 14-MAY-08 08.59.08.843679 PM | direct | 106 | 3 | 23034.6 | 156 | – |
| 2440 | 31-AUG-07 09.53.06.008765 PM | direct | 107 | 3 | 70576.9 | 156 | – |
| 2357 | 08-JAN-06 08.19.44.123456 PM | direct | 108 | 5 | 59872.4 | 158 | – |
| 2394 | 10-FEB-08 09.22.35.564789 PM | direct | 109 | 5 | 21863 | 158 | – |
| 2435 | 02-SEP-07 11.22.53.134567 PM | direct | 144 | 6 | 62303 | 159 | – |
| 2455 | 20-SEP-07 11.34.11.456789 AM | direct | 145 | 7 | 14087.5 | 160 | – |
| 2379 | 16-MAY-07 02.22.24.234567 AM | direct | 146 | 8 | 17848.2 | 161 | – |
| 2396 | 02-FEB-06 01.34.56.345678 AM | direct | 147 | 8 | 34930 | 161 | – |
| 2406 | 29-JUN-07 04.41.20.098765 AM | direct | 148 | 8 | 2854.2 | 161 | – |
| 2434 | 13-SEP-07 05.49.30.647893 AM | direct | 149 | 8 | 268651.8 | 161 | – |
| 2436 | 02-SEP-07 06.18.04.378034 AM | direct | 116 | 8 | 6394.8 | 161 | – |
| 2446 | 27-JUL-07 07.03.08.302945 AM | direct | 117 | 8 | 103679.3 | 161 | – |
| 2447 | 27-JUL-08 08.59.10.223344 AM | direct | 101 | 8 | 33893.6 | 161 | – |
| 2432 | 14-SEP-07 09.53.40.223345 AM | direct | 102 | 10 | 10523 | 163 | – |
| 2433 | 13-SEP-07 10.19.00.654279 AM | direct | 103 | 10 | 78 | 163 | – |
| 2355 | 26-JAN-06 09.22.51.962632 AM | online | 104 | 8 | 94513.5 | – | – |
| 2356 | 26-JAN-08 09.22.41.934562 AM | online | 105 | 5 | 29473.8 | – | – |
| 2359 | 08-JAN-06 09.34.13.112233 PM | online | 106 | 9 | 5543.1 | – | – |
| 2360 | 14-NOV-07 12.22.31.223344 PM | online | 107 | 4 | 990.4 | – | – |
| 2361 | 13-NOV-07 01.34.21.986210 PM | online | 108 | 8 | 120131.3 | – | – |
| 2362 | 13-NOV-07 02.41.10.619477 PM | online | 109 | 4 | 92829.4 | – | – |
| 2363 | 23-OCT-07 05.49.56.346122 PM | online | 144 | 0 | 10082.3 | – | – |
| 2364 | 28-AUG-07 06.18.45.942399 PM | online | 145 | 4 | 9500 | – | – |
| 2365 | 28-AUG-07 07.03.34.003399 PM | online | 146 | 9 | 27455.3 | – | – |
| 2366 | 28-AUG-07 08.59.23.144778 PM | online | 147 | 5 | 37319.4 | – | – |
| 2367 | 27-JUN-08 09.53.32.335522 PM | online | 148 | 10 | 144054.8 | – | – |
| 2368 | 26-JUN-08 10.19.43.190089 PM | online | 149 | 10 | 60065 | – | – |
| 2369 | 26-JUN-07 11.22.54.009932 PM | online | 116 | 0 | 11097.4 | – | – |
| 2370 | 27-JUN-08 12.22.11.647398 AM | online | 117 | 4 | 126 | – | – |
| 2371 | 16-MAY-07 01.34.56.113356 AM | online | 118 | 6 | 79405.6 | – | – |
| 2372 | 27-FEB-07 12.22.33.356789 AM | online | 119 | 9 | 16447.2 | – | – |
| 2373 | 27-FEB-08 01.34.51.220065 AM | online | 120 | 4 | 416 | – | – |
| 2374 | 27-FEB-08 02.41.45.109654 AM | online | 121 | 0 | 4797 | – | – |
| 2375 | 26-FEB-07 03.49.50.459233 AM | online | 122 | 2 | 103834.4 | – | – |
| 2376 | 07-JUN-07 06.18.08.883310 AM | online | 123 | 6 | 11006.2 | – | – |
| 2377 | 07-JUN-07 07.03.01.001100 AM | online | 141 | 5 | 38017.8 | – | – |
| 2378 | 24-MAY-07 08.59.10.010101 AM | online | 142 | 5 | 25691.3 | – | – |
| 2380 | 16-MAY-07 09.53.02.909090 AM | online | 143 | 3 | 27132.6 | – | – |
| 2382 | 14-MAY-08 10.19.03.828321 AM | online | 144 | 8 | 71173 | – | – |
| 2383 | 12-MAY-08 11.22.30.545103 AM | online | 145 | 8 | 36374.7 | – | – |
| 2384 | 12-MAY-08 12.22.34.525972 PM | online | 146 | 3 | 29249.1 | – | – |
| 2385 | 08-DEC-07 11.34.11.331392 AM | online | 147 | 4 | 295892 | – | – |
| 2386 | 06-DEC-07 12.22.34.225609 PM | online | 148 | 10 | 21116.9 | – | – |
| 2387 | 11-MAR-07 03.34.56.536966 PM | online | 149 | 5 | 52758.9 | – | – |
| 2388 | 04-JUN-07 04.41.12.554435 PM | online | 150 | 4 | 282694.3 | – | – |
| 2389 | 04-JUN-08 05.49.43.546954 PM | online | 151 | 4 | 17620 | – | – |
| 2390 | 18-NOV-07 04.18.50.546851 PM | online | 152 | 9 | 7616.8 | – | – |
| 2391 | 27-FEB-06 05.03.03.828330 PM | direct | 153 | 2 | 48070.6 | 156 | – |
| 2392 | 21-JUL-07 08.59.57.571057 PM | direct | 154 | 9 | 26632 | 161 | – |
| 2393 | 10-FEB-08 07.53.19.528202 PM | direct | 155 | 4 | 23431.9 | 161 | – |
| 2395 | 02-FEB-06 08.19.11.227550 PM | direct | 156 | 3 | 68501 | 163 | – |
| 2398 | 19-NOV-07 09.22.53.224175 PM | direct | 157 | 9 | 7110.3 | 163 | – |
| 2399 | 19-NOV-07 10.22.38.340990 PM | direct | 158 | 0 | 25270.3 | 161 | – |
| 2400 | 10-JUL-07 01.34.29.559387 AM | direct | 159 | 2 | 69286.4 | 161 | – |
| 2401 | 10-JUL-07 02.22.53.554822 AM | direct | 160 | 3 | 969.2 | 163 | – |
| 2402 | 02-JUL-07 03.34.44.665170 AM | direct | 161 | 8 | 600 | 154 | – |
| 2403 | 01-JUL-07 04.49.13.615512 PM | direct | 162 | 0 | 220 | 154 | – |
| 2404 | 01-JUL-07 04.49.13.664085 PM | direct | 163 | 6 | 510 | 158 | – |
| 2405 | 01-JUL-07 04.49.13.678123 PM | direct | 164 | 5 | 1233 | 159 | – |
| 2407 | 29-JUN-07 07.03.21.526005 AM | direct | 165 | 9 | 2519 | 155 | – |
| 2408 | 29-JUN-07 08.59.31.333617 AM | direct | 166 | 1 | 309 | 158 | – |
| 2409 | 29-JUN-07 09.53.41.984501 AM | direct | 167 | 2 | 48 | 154 | – |
| 2410 | 24-MAY-08 10.19.51.985501 AM | direct | 168 | 6 | 45175 | 156 | – |
| 2411 | 24-MAY-07 11.22.10.548639 AM | direct | 169 | 8 | 15760.5 | 156 | – |
| 2412 | 29-MAR-06 10.22.09.509801 AM | direct | 170 | 9 | 66816 | 158 | – |
| 2413 | 29-MAR-08 01.34.04.525934 PM | direct | 101 | 5 | 48552 | 161 | – |
| 2414 | 29-MAR-07 02.22.40.536996 PM | direct | 102 | 8 | 10794.6 | 153 | – |
| 2415 | 29-MAR-06 01.34.50.545196 PM | direct | 103 | 6 | 310 | 161 | – |
| 2416 | 29-MAR-07 04.41.20.945676 PM | direct | 104 | 6 | 384 | 160 | – |
| 2417 | 20-MAR-07 05.49.10.974352 PM | direct | 105 | 5 | 1926.6 | 163 | – |
| 2418 | 20-MAR-04 04.18.21.862632 PM | direct | 106 | 4 | 5546.6 | 163 | – |
| 2419 | 20-MAR-07 07.03.32.764632 PM | direct | 107 | 3 | 31574 | 160 | – |
| 2420 | 13-MAR-07 08.59.43.666320 PM | direct | 108 | 2 | 29750 | 160 | – |
| 2421 | 12-MAR-07 09.53.54.562432 PM | direct | 109 | 1 | 72836 | – | – |
| 2422 | 16-DEC-07 08.19.55.462332 PM | direct | 144 | 2 | 11188.5 | 153 | – |
| 2423 | 21-NOV-07 10.22.33.362632 AM | direct | 145 | 3 | 10367.7 | 160 | – |
| 2424 | 21-NOV-07 10.22.33.263332 AM | direct | 146 | 4 | 13824 | 153 | – |
| 2425 | 16-NOV-06 11.34.22.162552 PM | direct | 147 | 5 | 1500.8 | 163 | – |
| 2426 | 17-NOV-06 12.22.11.262552 AM | direct | 148 | 6 | 7200 | – | – |
| 2427 | 10-NOV-07 01.34.22.362124 AM | direct | 149 | 7 | 9055 | 163 | – |
| 2428 | 10-NOV-07 02.41.34.463567 AM | direct | 116 | 8 | 14685.8 | – | – |
| 2429 | 10-NOV-07 03.49.25.526321 AM | direct | 117 | 9 | 50125 | 154 | – |
| 2430 | 02-OCT-07 06.18.36.663332 AM | direct | 101 | 8 | 29669.9 | 159 | – |
| 2431 | 14-SEP-06 07.03.04.763452 AM | direct | 102 | 1 | 5610.6 | 163 | – |
| 2437 | 01-SEP-06 08.59.15.826132 AM | direct | 103 | 4 | 13550 | 163 | – |
| 2438 | 01-SEP-07 09.53.26.934626 AM | direct | 104 | 0 | 5451 | 154 | – |
| 2439 | 31-AUG-07 10.19.37.811132 AM | direct | 105 | 1 | 22150.1 | 159 | – |
| 2441 | 01-AUG-08 11.22.48.734526 AM | direct | 106 | 5 | 2075.2 | 160 | – |
| 2442 | 27-JUL-06 12.22.59.662632 PM | direct | 107 | 9 | 52471.9 | 154 | – |
| 2443 | 27-JUL-06 01.34.16.562632 PM | direct | 108 | 0 | 3646 | 154 | – |
| 2444 | 27-JUL-07 02.22.27.462632 PM | direct | 109 | 1 | 77727.2 | 155 | – |
| 2445 | 27-JUL-06 03.34.38.362632 PM | direct | 144 | 8 | 5537.8 | 158 | – |
| 2448 | 18-JUN-07 04.41.49.262632 PM | direct | 145 | 5 | 1388 | 158 | – |
| 2449 | 13-JUN-07 05.49.07.162632 PM | direct | 146 | 6 | 86 | 155 | – |
| 2450 | 11-APR-07 06.18.10.362632 PM | direct | 147 | 3 | 1636 | 159 | – |
| 2451 | 17-DEC-07 05.03.52.562632 PM | direct | 148 | 7 | 10474.6 | 154 | – |
| 2452 | 06-OCT-07 08.59.43.462632 PM | direct | 149 | 5 | 12589 | 159 | – |
| 2453 | 04-OCT-07 09.53.34.362632 PM | direct | 116 | 0 | 129 | 153 | – |
| 2456 | 07-NOV-06 07.53.25.989889 PM | direct | 117 | 0 | 3878.4 | 163 | – |
| 2457 | 31-OCT-07 11.22.16.162632 PM | direct | 118 | 5 | 21586.2 | 159 | – |
COMPUTE THE MAXIMUM ORDER TOTAL ACROSS ALL ORDERS
SELECT
MAX(oe.orders.order_total) AS maximum_order_total
FROM
oe.orders;
| maximum_order_total |
|---|
| 295892 |
In the example code above, note that a GROUP BY clause is not present because the code returns a single row representing the maximum order total value across all orders (295892).
COMPUTE THE MAXIMUM ORDER TOTAL FOR EACH CUSTOMER
SELECT
oe.orders.customer_id,
MAX(oe.orders.order_total) AS maximum_order_total
FROM
oe.orders
GROUP BY
oe.orders.customer_id;
| customer_id | maximum_order_total |
|---|---|
| 107 | 70576.9 |
| 108 | 120131.3 |
| 158 | 25270.3 |
| 161 | 600 |
| 166 | 309 |
| 105 | 29473.8 |
| 109 | 92829.4 |
| 143 | 27132.6 |
| 159 | 69286.4 |
| 162 | 220 |
| 163 | 510 |
| 168 | 45175 |
| 104 | 94513.5 |
| 118 | 79405.6 |
| 145 | 36374.7 |
| 121 | 4797 |
| 141 | 38017.8 |
| 155 | 23431.9 |
| 101 | 78279.6 |
| 103 | 13550 |
| 116 | 14685.8 |
| 120 | 416 |
| 142 | 25691.3 |
| 151 | 17620 |
| 156 | 68501 |
| 157 | 7110.3 |
| 169 | 15760.5 |
| 146 | 29249.1 |
| 148 | 144054.8 |
| 149 | 268651.8 |
| 122 | 103834.4 |
| 152 | 7616.8 |
| 170 | 66816 |
| 144 | 71173 |
| 119 | 16447.2 |
| 153 | 48070.6 |
| 164 | 1233 |
| 167 | 48 |
| 102 | 42283.2 |
| 106 | 23034.6 |
| 147 | 295892 |
| 117 | 103679.3 |
| 123 | 11006.2 |
| 150 | 282694.3 |
| 154 | 26632 |
| 160 | 969.2 |
| 165 | 2519 |
When an aggregate must be computed across and for each set of grouped rows, a GROUP BY clause is necessary. Here, the rows have been grouped by customer ID and for each of those sets of grouped rows, the maximum order total is computed.
COMPUTE THE MAXIMUM ORDER TOTAL FOR THE TOP CUSTOMER(S) IN TERMS OF ORDERS PLACED
SELECT
oe.orders.customer_id,
MAX(oe.orders.order_total) AS maximum_order_total
FROM
oe.orders
GROUP BY
oe.orders.customer_id
HAVING
COUNT(*) = (
SELECT
MAX(order_counts.order_count)
FROM (
SELECT
COUNT(*) AS order_count
FROM
oe.orders
GROUP BY
oe.orders.customer_id
) order_counts
);
| customer_id | maximum_order_total |
|---|---|
| 145 | 36374.7 |
| 146 | 29249.1 |
| 148 | 144054.8 |
| 149 | 268651.8 |
| 144 | 71173 |
| 147 | 295892 |
The solution here is largely the same as computing the maximum order total for each customer; however, the addition of the HAVING clause permits the maximum order total to be computed only across the set(s) of grouped rows corresponding to the top customer(s) in terms of number of orders placed. Problems such as this one are often easier to tackle when the problem is broken down into two or more subproblems or steps. This problem can be broken down into three steps.
The first step is to write a query that returns the maximum order total for each customer. The second step is to write a query that returns a single value representing the largest number of orders placed by any customer. Luckily, neither of these problems are terribly difficult when solved individually. After solving for the two queries, it’s a simple as placing the query from step two in the HAVING clause as a subquery, as seen above. The most difficult part is realizing that this seemingly complex problem is a couple of simple problems that, when solved individually, the complexity disappears. Break-down problems into several subproblems or steps when you can.
RETRIEVE ORDER DETAILS FOR THE MOST RECENT ORDER PLACED
SELECT
oe.orders.order_id,
oe.orders.order_date,
oe.orders.customer_id,
oe.orders.order_total
FROM
oe.orders
WHERE
oe.orders.order_date = (
SELECT
MAX(oe.orders.order_date)
FROM
oe.orders
);
| order_id | order_date | customer_id | order_total |
|---|---|---|---|
| 2441 | 01-AUG-08 11.22.48.734526 AM | 106 | 2075.2 |
The solution above utilizes a subquery in the WHERE clause. The subquery returns a single value, the maximum order date value within the orders table. This value is then compared to each row’s order date value in the outer query and if the values match, the corresponding row is returned. If multiple orders were placed at the same time (including fractional seconds), then more than one row would be returned, one for each order placed at that time.
RETRIEVE ORDER DETAILS FOR EACH CUSTOMER’S LARGEST ORDER(S) PLACED IN TERMS OF AMOUNT SPENT
-- Using a JOIN to a derived table to solve.
SELECT
oe.orders.order_id,
oe.orders.order_date,
oe.orders.customer_id,
oe.orders.order_total
FROM
oe.orders
INNER JOIN (
SELECT
oe.orders.customer_id,
MAX(oe.orders.order_total) AS order_total
FROM
oe.orders
GROUP BY
oe.orders.customer_id
) largest_order
ON oe.orders.customer_id = largest_order.customer_id
AND oe.orders.order_total = largest_order.order_total;
-- Using common table expression and DENSE_RANK() to solve.
WITH largest_order AS (
SELECT
oe.orders.order_id,
oe.orders.order_date,
oe.orders.customer_id,
oe.orders.order_total,
DENSE_RANK() OVER (
PARTITION BY oe.orders.customer_id
ORDER BY oe.orders.order_total DESC
) AS order_rank
FROM
oe.orders
)
SELECT
largest_order.order_id,
largest_order.order_date,
largest_order.customer_id,
largest_order.order_total
FROM
largest_order
WHERE
largest_order.order_rank = 1;
| order_id | order_date | customer_id | order_total |
|---|---|---|---|
| 2458 | 16-AUG-07 03.34.12.234359 PM | 101 | 78279.6 |
| 2397 | 19-NOV-07 02.41.54.696211 PM | 102 | 42283.2 |
| 2381 | 14-MAY-08 08.59.08.843679 PM | 106 | 23034.6 |
| 2440 | 31-AUG-07 09.53.06.008765 PM | 107 | 70576.9 |
| 2434 | 13-SEP-07 05.49.30.647893 AM | 149 | 268651.8 |
| 2446 | 27-JUL-07 07.03.08.302945 AM | 117 | 103679.3 |
| 2355 | 26-JAN-06 09.22.51.962632 AM | 104 | 94513.5 |
| 2356 | 26-JAN-08 09.22.41.934562 AM | 105 | 29473.8 |
| 2361 | 13-NOV-07 01.34.21.986210 PM | 108 | 120131.3 |
| 2362 | 13-NOV-07 02.41.10.619477 PM | 109 | 92829.4 |
| 2367 | 27-JUN-08 09.53.32.335522 PM | 148 | 144054.8 |
| 2371 | 16-MAY-07 01.34.56.113356 AM | 118 | 79405.6 |
| 2372 | 27-FEB-07 12.22.33.356789 AM | 119 | 16447.2 |
| 2373 | 27-FEB-08 01.34.51.220065 AM | 120 | 416 |
| 2374 | 27-FEB-08 02.41.45.109654 AM | 121 | 4797 |
| 2375 | 26-FEB-07 03.49.50.459233 AM | 122 | 103834.4 |
| 2376 | 07-JUN-07 06.18.08.883310 AM | 123 | 11006.2 |
| 2377 | 07-JUN-07 07.03.01.001100 AM | 141 | 38017.8 |
| 2378 | 24-MAY-07 08.59.10.010101 AM | 142 | 25691.3 |
| 2380 | 16-MAY-07 09.53.02.909090 AM | 143 | 27132.6 |
| 2382 | 14-MAY-08 10.19.03.828321 AM | 144 | 71173 |
| 2383 | 12-MAY-08 11.22.30.545103 AM | 145 | 36374.7 |
| 2384 | 12-MAY-08 12.22.34.525972 PM | 146 | 29249.1 |
| 2385 | 08-DEC-07 11.34.11.331392 AM | 147 | 295892 |
| 2388 | 04-JUN-07 04.41.12.554435 PM | 150 | 282694.3 |
| 2389 | 04-JUN-08 05.49.43.546954 PM | 151 | 17620 |
| 2390 | 18-NOV-07 04.18.50.546851 PM | 152 | 7616.8 |
| 2391 | 27-FEB-06 05.03.03.828330 PM | 153 | 48070.6 |
| 2392 | 21-JUL-07 08.59.57.571057 PM | 154 | 26632 |
| 2393 | 10-FEB-08 07.53.19.528202 PM | 155 | 23431.9 |
| 2395 | 02-FEB-06 08.19.11.227550 PM | 156 | 68501 |
| 2398 | 19-NOV-07 09.22.53.224175 PM | 157 | 7110.3 |
| 2399 | 19-NOV-07 10.22.38.340990 PM | 158 | 25270.3 |
| 2400 | 10-JUL-07 01.34.29.559387 AM | 159 | 69286.4 |
| 2401 | 10-JUL-07 02.22.53.554822 AM | 160 | 969.2 |
| 2402 | 02-JUL-07 03.34.44.665170 AM | 161 | 600 |
| 2403 | 01-JUL-07 04.49.13.615512 PM | 162 | 220 |
| 2404 | 01-JUL-07 04.49.13.664085 PM | 163 | 510 |
| 2405 | 01-JUL-07 04.49.13.678123 PM | 164 | 1233 |
| 2407 | 29-JUN-07 07.03.21.526005 AM | 165 | 2519 |
| 2408 | 29-JUN-07 08.59.31.333617 AM | 166 | 309 |
| 2409 | 29-JUN-07 09.53.41.984501 AM | 167 | 48 |
| 2410 | 24-MAY-08 10.19.51.985501 AM | 168 | 45175 |
| 2411 | 24-MAY-07 11.22.10.548639 AM | 169 | 15760.5 |
| 2412 | 29-MAR-06 10.22.09.509801 AM | 170 | 66816 |
| 2428 | 10-NOV-07 02.41.34.463567 AM | 116 | 14685.8 |
| 2437 | 01-SEP-06 08.59.15.826132 AM | 103 | 13550 |
Retrieving the order details for each customer’s orders is straightforward. The difficulty in this problem is having to filter the orders to only the customer’s largest order(s) in terms of amount spent (i.e., order total). Like the problem above, this one can be broken down into a couple of steps.
First, we need to write a query returning the customer ID and corresponding order total associated with each customer’s largest order(s). We’ll use this information to filter the orders table to the largest order(s) placed by each customer by joining it to an outer query containing the details of the associated and matched order. You’ll notice we have two conditions in our ON clause. First, the customer ID in the outer-query and subquery must match and, second, the order total must match. The latter of the two is less obvious, but critical to our solution because we only want the largest order placed by each customer. In the absence of the second condition filtering on order total, the same result-set as retrieving all orders from the orders table would be returned.
A common table expression (CTE), containing each the details of each customer’s orders and the rank associated with that order when computed across only the respective customer’s orders, is used in the second solution. The SELECT statement that follows the CTE filters the temporary result set to only those records associated with each customers largest order(s) in terms of amount spent (i.e., largest_order.rank = 1).
Knowledge Check
Need more practice or simply wish to test your understanding? Give a few of the practice problems I’ve provided in the SQL Practice Problems section a try.