The COUNT function computes the number of times an item (value) appears in 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 TOTAL NUMBER OF ORDERS
SELECT
COUNT(*) AS order_count
FROM
oe.orders;
| order_count |
|---|
| 105 |
In the example code above, note that a GROUP BY clause is not present because the code returns a single row representing the total number of orders across the entire orders table (105). Here, we’ve taken advantage of knowing each row within the orders table represents a single order. Therefore, to compute the total number of orders within the orders table, simply the number of rows needs to be computed. Keep this in mind for the examples that follow.
COMPUTE THE TOTAL NUMBER OF ORDER FOR EACH CUSTOMER
SELECT
oe.orders.customer_id,
COUNT(*) AS order_count
FROM
oe.orders
GROUP BY
oe.orders.customer_id;
| customer_id | order_count |
|---|---|
| 107 | 4 |
| 108 | 4 |
| 158 | 1 |
| 161 | 1 |
| 166 | 1 |
| 105 | 4 |
| 109 | 4 |
| 143 | 1 |
| 159 | 1 |
| 162 | 1 |
| 163 | 1 |
| 168 | 1 |
| 104 | 4 |
| 118 | 2 |
| 145 | 5 |
| 121 | 1 |
| 141 | 1 |
| 155 | 1 |
| 101 | 4 |
| 103 | 4 |
| 116 | 4 |
| 120 | 1 |
| 142 | 1 |
| 151 | 1 |
| 156 | 1 |
| 157 | 1 |
| 169 | 1 |
| 146 | 5 |
| 148 | 5 |
| 149 | 5 |
| 122 | 1 |
| 152 | 1 |
| 170 | 1 |
| 144 | 5 |
| 119 | 1 |
| 153 | 1 |
| 164 | 1 |
| 167 | 1 |
| 102 | 4 |
| 106 | 4 |
| 147 | 5 |
| 117 | 4 |
| 123 | 1 |
| 150 | 1 |
| 154 | 1 |
| 160 | 1 |
| 165 | 1 |
Computing the total number of orders for each customer requires that we simply build onto our previous solution. A GROUP BY clause is necessary to retrieve the number of orders for each customer. The result set will contain one row of data per customer. Within each row will be the customer ID and the corresponding order count value.
RETRIEVE ONLY THOSE CUSTOMERS WITH FIVE OR MORE ORDERS
SELECT
oe.orders.customer_id,
COUNT(*) AS order_count
FROM
oe.orders
GROUP BY
oe.orders.customer_id
HAVING
COUNT(*) >= 5;
| customer_id | order_count |
|---|---|
| 145 | 5 |
| 146 | 5 |
| 148 | 5 |
| 149 | 5 |
| 144 | 5 |
| 147 | 5 |
Like the approach taken in the previous example, simply build onto the previous solution. A HAVING clause is necessary to filter the grouped rows (i.e., the individual rows containing each customer’s order count). Filter by the number of rows corresponding to each customer (i.e., COUNT(*)).
RETRIEVE THE TOP CUSTOMER(S) IN TERMS OF ORDER COUNT
-- Using a subquery within a subquery.
SELECT
oe.customers.customer_id,
COUNT(oe.orders.order_id) AS order_count
FROM
oe.customers
INNER JOIN
oe.orders
ON oe.customers.customer_id = oe.orders.customer_id
GROUP BY
oe.customers.customer_id
HAVING
COUNT(oe.orders.order_id) = (
SELECT
MAX(order_counts.order_count)
FROM (
SELECT
COUNT(oe.orders.order_id) AS order_count
FROM
oe.orders
GROUP BY
oe.orders.customer_id
) order_counts
);
-- Using a subquery in the HAVING clause to solve (nested-aggregate).
SELECT
oe.customers.customer_id,
COUNT(oe.orders.order_id) AS order_count
FROM
oe.customers
INNER JOIN
oe.orders
ON oe.customers.customer_id = oe.orders.customer_id
GROUP BY
oe.customers.customer_id
HAVING
COUNT(oe.orders.order_id) = (
SELECT
MAX(COUNT(oe.orders.order_id))
FROM
oe.orders
GROUP BY
oe.orders.customer_id
);
-- Using subquery in the HAVING clause with the modified comparison operator, ALL.
SELECT
oe.orders.customer_id,
COUNT(*) AS order_count
FROM
oe.orders
GROUP BY
oe.orders.customer_id
HAVING
COUNT(*) >= ALL (
SELECT
COUNT(*)
FROM
oe.orders
GROUP BY
oe.orders.customer_id
);
| customer_id | order_count |
|---|---|
| 145 | 5 |
| 146 | 5 |
| 148 | 5 |
| 149 | 5 |
| 144 | 5 |
| 147 | 5 |
The first and second solutions rely on a subquery in the HAVING clause. The subquery returns a single value representing the largest number of orders placed by any given customer. The number of orders placed by each customer is subsequently compared to this value with rows in the outer query containing the same value being kept in the result-set. Take caution in implementing the second solution as it contains a nested aggregate. Many RDBMS do not permit the direct nesting of aggregates and require the additional step seen in the first solution where the number of orders placed for each customer is computed, treated as a derived table or temporary result-set, and finally the maximum of those order counts is computed. The third solution above utilizes a subquery in the HAVING clause in conjunction with the modified comparison operator, ALL. The subquery returns a list of values with each value representing an individual customer’s order count. Each customer’s order count computed in the outer query is compared to the list generated by the subquery. If the customer’s order count value is greater than or equal the all the values in the list, then the row for that customer is included in the result set. It can be inferred that if the customer’s order count value, when compared to each individual value generated by the subquery, is greater than or equal all of the values, then it must be the largest value.
COUNT(*) vs. COUNT(attribute)
When using the COUNT function, it is important to understand the difference in the function’s behavior when the argument passed to the function is an attribute instead of the “*” character. When an attribute is passed to the function, the count returned represents the number of rows with non-null values for the specified attribute while COUNT(*) simply represents the number of rows returned. For clarity, see the example code and corresponding output below.
SELECT
COUNT(*) AS order_count,
COUNT(oe.orders.sales_rep_id) AS assisted_order_count
FROM
oe.orders;
| order_count | assisted_order_count |
|---|---|
| 105 | 70 |
In the output above, COUNT(*) returns the number of rows (i.e., orders) within the orders table. When the sales representative ID attribute is passed into the COUNT function, the number of rows with a sales representative ID value populated is returned (70). This value tells us seventy orders were placed with the assistance of a sales representative.
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.