简体   繁体   中英

SQL Server 2005 GROUP BY and COUNT query for each month

I have a SQL Server 2005 table named Rentals :

RentalID
Book
Date

I want to return, using a query, for each book, how many rentals were in each month for a given year.

The results should look something like this:

+--------------------------------+-----+-----+-----+  
|              Book              | Jan | Feb | Mar |
+--------------------------------+-----+-----+-----+  
| Isaac Asimov - Foundation      |   2 |   5 |   3 |  
| H.G. Wells - War of the Worlds |   4 |   3 |   1 |  
| Frank Herbert - Dune           |   7 |   4 |   6 |
+--------------------------------+-----+-----+-----+

My query so far:

SELECT
Book, 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=1 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=2 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=3 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=4 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=5 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=6 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=7 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=8 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=9 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=10 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=11 AND year(Date)=2011), 
(SELECT COUNT(*) FROM Rentals WHERE month(Date)=12 AND year(Date)=2011) 
FROM Rentals 
GROUP BY Book

This can be written much simpler by using a CASE expression inside of an aggregate function. This process is called PIVOT:

select book,
  sum(case when month(Date) = 1 then 1 else 0 end) Jan,
  sum(case when month(Date) = 2 then 1 else 0 end) Feb,
  sum(case when month(Date) = 3 then 1 else 0 end) Mar,
  sum(case when month(Date) = 4 then 1 else 0 end) Apr,
  sum(case when month(Date) = 5 then 1 else 0 end) May,
  sum(case when month(Date) = 6 then 1 else 0 end) Jun,
  sum(case when month(Date) = 7 then 1 else 0 end) Jul,
  sum(case when month(Date) = 8 then 1 else 0 end) Aug,
  sum(case when month(Date) = 9 then 1 else 0 end) Sep,
  sum(case when month(Date) = 10 then 1 else 0 end) Oct,
  sum(case when month(Date) = 11 then 1 else 0 end) Nov,
  sum(case when month(Date) = 12 then 1 else 0 end) Dec
from Rentals
where year(date) = 2011
group by book;

See SQL Fiddle with Demo . Instead of querying the table multiple times for each column, you use conditional aggregation to get the count for each book during the month and year.

If you use pivot the code is much easier to maintain,

SELECT 
    BOOK,
    [1] as Jan ,
    [2] as Feb,
    [3] as Mar,
    [4] as Apr,
    [5] as May,
    [6] as Jun,
    [7] as Jul,
    [8] as Aug,
    [9] as Sep,
    [10] as Oct,
    [11] as Nov,
    [12] as Dec 
FROM
(
    SELECT 
       BOOK , 
       DATEPART(MONTH,[DATE]) AS PER 
    FROM 
        Rentals 
    WHERE 
        DATEPART(YEAR,[DATE]) = 2014
) AS P PIVOT 
    (
    COUNT(PER) FOR PER IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
    ) AS DATA

Simple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM