简体   繁体   中英

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?

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')

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.

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.

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

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