Reputation: 13
I'm quite new to SQL and I need your help.
I want to SELECT
all rows in column YM
(yearmonth) in range 201801
- 201804
even if the criteria (001) is not exists for some months.
table pod11
:
YM code hour
------------------------------------
201712 005 32
201712 002 16
201712 003 24
201712 007 112
201801 001 112
201801 003 12
201801 005 24
201801 007 64
201802 001 64
201802 002 128
201803 005 32
201803 002 16
201804 003 24
201804 007 112
201804 008 86
I used this:
SELECT YM,code,hour
FROM pod11
WHERE YM >= '201801' AND YM <= '201804' and code = '001'
GROUP by YM,code,hour
ORDER BY YM
I got this:
YM code hour
------------------------------------
201801 001 112
201802 001 64
Any suggestions on how I could write a query to achieve this?
YM code hour
------------------------------------
201801 001 112
201802 001 64
201803 0 0
201804 0 0
Upvotes: 1
Views: 100
Reputation: 1270061
I was wondering if this could be done without subqueries. I think it can be:
select top (1) with ties YM,
(case when code = '001' then hour else 0 end) as code,
(case when code = '001' then code else 0 end) as hour
from pod11
where YM between '201801' and '201804'
order by rank() over (partition by ym
order by (case when code = '001' then 1 else 2 end),
(case when code <> '001' then hour end)
)
Upvotes: 1
Reputation: 1
you can join your table on itself:
select p1.YM
,coalesce(p2.code,'0') as code
,coalesce(p2.hour,'0') as hour
from pod11 As p1
left join pod11 As p2
on p2.YM = p1.YM
and p2.code = p1.code
where p1.YM between '201801' and '201804'
and coalesce(p2.code,'0') in ('0', '001')
Upvotes: 0
Reputation: 43584
MSSQL:
SELECT
tableYM.YM,
ISNULL(pod11.code, 0) AS code,
ISNULL(SUM(pod11.hour), 0) AS hour
FROM (
SELECT DISTINCT YM FROM pod11 WHERE YM >= '201801' AND YM <= '201804'
) tableYM LEFT JOIN pod11 ON tableYM.YM = pod11.YM AND pod11.code = '001'
GROUP BY pod11.code, tableYM.YM
ORDER BY tableYM.YM
MySQL:
SELECT
tableYM.YM,
IFNULL(pod11.code, 0) AS code,
IFNULL(SUM(pod11.hour), 0) AS hour
FROM (
SELECT DISTINCT YM FROM pod11 WHERE YM >= '201801' AND YM <= '201804'
) tableYM LEFT JOIN pod11 ON tableYM.YM = pod11.YM AND pod11.code = '001'
GROUP BY pod11.code, tableYM.YM
ORDER BY tableYM.YM
Upvotes: 0
Reputation: 521629
One option is to use a union to bring in records for the months which have no matching code
records. In my output, there is data for 201712
, because you did not specify a reason why it should not appear, and it has no matching code data. If you don't want that record in there, it would be easy enough to remove it in the WHERE
clause.
SELECT YM, code, hour
FROM pod11
WHERE YM BETWEEN '201801' AND '201804' AND code = '001'
GROUP BY YM, code, hour
UNION ALL
SELECT DISTINCT t1.YM, 0, 0
FROM pod11 t1
WHERE NOT EXISTS (SELECT 1 FROM pod11 t2 WHERE t1.YM = t2.YM AND t2.code = '001')
ORDER BY YM;
Upvotes: 0
Reputation: 1399
SELECT YM, COALESCE(code,0) code, COALESCE(hour,0) hour
(
SELECT YM,code,hour
FROM pod11
WHERE YM >= '201801' AND YM <= '201804' and code = '001'
GROUP by YM,code,hour
RIGHT JOIN
(SELECT 201801 as YM
UNION
SELECT 201802
UNION
SELECT 201803
UNION
SELECT 201804
) as t
ON pod11. YM = t.YM
)
ORDER BY YM
You can store the year in different table and query from that or if you know all the years will be there in pod11 table i.e. 201801 to 201804, then you can query from that table with range and distinct
Upvotes: 0