Centell
Centell

Reputation: 409

How can I make this SQL query more elegant?

This is my MySQL query for getting count values...

SELECT 1 AS id,
       '2016' AS Year,
       MAX( IF( Month = '01', Count, 0 ) ) AS 'VAL01',
       MAX( IF( Month = '02', Count, 0 ) ) AS 'VAL02',
       MAX( IF( Month = '03', Count, 0 ) ) AS 'VAL03',
       MAX( IF( Month = '04', Count, 0 ) ) AS 'VAL04',
       MAX( IF( Month = '05', Count, 0 ) ) AS 'VAL05',
       MAX( IF( Month = '06', Count, 0 ) ) AS 'VAL06',
       MAX( IF( Month = '07', Count, 0 ) ) AS 'VAL07',
       MAX( IF( Month = '08', Count, 0 ) ) AS 'VAL08',
       MAX( IF( Month = '09', Count, 0 ) ) AS 'VAL09',
       MAX( IF( Month = '10', Count, 0 ) ) AS 'VAL10',
       MAX( IF( Month = '11', Count, 0 ) ) AS 'VAL11',
       MAX( IF( Month = '12', Count, 0 ) ) AS 'VAL12',
       SUM( Count ) AS Total
FROM ( SELECT DATE_FORMAT( created_at, '%m' ) AS Month,
              COUNT( 1 ) AS Count
       FROM reservations
       WHERE DATE_FORMAT( created_at, '%Y' ) = '2016'
       GROUP BY DATE_FORMAT( created_at, '%m' )
     ) AS T1
UNION
SELECT 2 AS id,
       '2017' AS Year,
       MAX( IF( Month = '01', Count, 0 ) ) AS 'VAL01',
       MAX( IF( Month = '02', Count, 0 ) ) AS 'VAL02',
       MAX( IF( Month = '03', Count, 0 ) ) AS 'VAL03',
       MAX( IF( Month = '04', Count, 0 ) ) AS 'VAL04',
       MAX( IF( Month = '05', Count, 0 ) ) AS 'VAL05',
       MAX( IF( Month = '06', Count, 0 ) ) AS 'VAL06',
       MAX( IF( Month = '07', Count, 0 ) ) AS 'VAL07',
       MAX( IF( Month = '08', Count, 0 ) ) AS 'VAL08',
       MAX( IF( Month = '09', Count, 0 ) ) AS 'VAL09',
       MAX( IF( Month = '10', Count, 0 ) ) AS 'VAL10',
       MAX( IF( Month = '11', Count, 0 ) ) AS 'VAL11',
       MAX( IF( Month = '12', Count, 0 ) ) AS 'VAL12',
       SUM( Count ) AS Total
FROM ( SELECT DATE_FORMAT( created_at, '%m' ) AS Month,
              COUNT( 1 ) AS Count
       FROM reservations
       WHERE DATE_FORMAT( created_at, '%Y' ) = '2017'
       GROUP BY DATE_FORMAT( created_at, '%m' )
     ) AS T2

It returns (for example)...

+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
| id | Year | VAL01 | VAL02 | VAL03 | VAL04 | VAL05 | VAL06 | ... | VAL12 | Total |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
|  1 | 2016 |     0 |     0 |   150 |   190 |   200 |   220 | ... |   160 |  1242 |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+
|  2 | 2017 |   300 |   300 |   600 |   600 |   700 |     0 | ... |     0 |  2500 |
+----+------+-------+-------+-------+-------+-------+-------+-----+-------+-------+

My query has many problems. It can't use the year 2018 and it should use UNION again and again.

How can I make my SQL query more beautiful?

Upvotes: 0

Views: 126

Answers (4)

Madhivanan
Madhivanan

Reputation: 13700

Try this

select 
date_format(created_at,'%Y') as Year,
sum(case when date_format(created_at,'%m')='01' then 1 else 0 end) as val01,
sum(case when date_format(created_at,'%m')='02' then 1 else 0 end) as val02,
sum(case when date_format(created_at,'%m')='03' then 1 else 0 end) as val03,
sum(case when date_format(created_at,'%m')='04' then 1 else 0 end) as val04,
sum(case when date_format(created_at,'%m')='05' then 1 else 0 end) as val05,
sum(case when date_format(created_at,'%m')='06' then 1 else 0 end) as val06,
sum(case when date_format(created_at,'%m')='07' then 1 else 0 end) as val07,
sum(case when date_format(created_at,'%m')='08' then 1 else 0 end) as val08,
sum(case when date_format(created_at,'%m')='09' then 1 else 0 end) as val09,
sum(case when date_format(created_at,'%m')='10' then 1 else 0 end) as val10,
sum(case when date_format(created_at,'%m')='11' then 1 else 0 end) as val11,
sum(case when date_format(created_at,'%m')='12' then 1 else 0 end) as val12,
count(*) as total 
from reservations
group by date_format(created_at,'%Y')

Upvotes: 1

Trung Duong
Trung Duong

Reputation: 3475

You could try this query

SELECT id, 
       Year, 
       SUM(CASE WHEN Month='01' THEN MonthCount ELSE 0 END) AS 'VAL01',
       SUM(CASE WHEN Month='02' THEN MonthCount ELSE 0 END) AS 'VAL02',
       SUM(CASE WHEN Month='03' THEN MonthCount ELSE 0 END) AS 'VAL03',
       SUM(CASE WHEN Month='04' THEN MonthCount ELSE 0 END) AS 'VAL04',
       SUM(CASE WHEN Month='05' THEN MonthCount ELSE 0 END) AS 'VAL05',
       SUM(CASE WHEN Month='06' THEN MonthCount ELSE 0 END) AS 'VAL06',
       SUM(CASE WHEN Month='07' THEN MonthCount ELSE 0 END) AS 'VAL07',
       SUM(CASE WHEN Month='08' THEN MonthCount ELSE 0 END) AS 'VAL08',
       SUM(CASE WHEN Month='09' THEN MonthCount ELSE 0 END) AS 'VAL09',
       SUM(CASE WHEN Month='10' THEN MonthCount ELSE 0 END) AS 'VAL10',
       SUM(CASE WHEN Month='11' THEN MonthCount ELSE 0 END) AS 'VAL11',
       SUM(CASE WHEN Month='12' THEN MonthCount ELSE 0 END) AS 'VAL12',
       SUM(MonthCount) AS Total        
FROM ( 
           SELECT 
                    CASE 
                             WHEN Date_format(created_at, '%Y') = '2016' THEN 1 
                             WHEN Date_format(created_at, '%Y') = '2017' THEN 2 
                             WHEN Date_format(created_at, '%Y') = '2018' THEN 3 
                    END                           AS id, 
                    Date_format(created_at, '%Y') AS Year, 
                    Date_format(created_at, '%m') AS Month, 
                    COUNT(1)                      AS MonthCount 
           FROM     reservations 
           WHERE    Date_format(created_at, '%Y') IN ('2016', '2017', '2018') 
           GROUP BY Date_format(created_at, '%Y-%m')) AS ByMonth 
GROUP BY id, Year

Upvotes: 0

Sagar Gangwal
Sagar Gangwal

Reputation: 7947

You can try with below query

SELECT YEAR,SUM(VAL01) VAL02,SUM(VAL02) VAL02,SUM(VAL03) VAL3
FROM
(
       SELECT date_format(created_at,'%Y') YEAR,
      CASE WHEN date_format(created_at,'%m')=1 THEN 1 ELSE 0 END AS VAL01,
      CASE WHEN date_format(created_at,'%m')=2 THEN 1 ELSE 0 END AS VAL02,
       CASE WHEN date_format(created_at,'%m')=3 THEN 1 ELSE 0 END AS VAL03
       FROM reservations 

)t
 GROUP BY YEAR

Hope this will helps.

Upvotes: 0

Shailesh Pratapwar
Shailesh Pratapwar

Reputation: 4224

If this had been Oracle, you could have used Function based index on column Created_at and using the same function (EXTRACT in this case) in your query:

CREATE INDEX IDX1 ON RESERVATIONS (EXTRACT(YEAR FROM CREATED_AT))

Since, this is MySQL, try using this as alternative. Make sure after creating the index, it is getting used by verifying the Query plan.

Upvotes: 0

Related Questions