User Attendance Date Year and Month Wise - sql

I've a requirement to show user attendance year and month wise. Here is a sample
how it would look - Very basic:
Year - Jan - Feb
2018 - 26 - 20
2019 - 20 - 22
The data is retrieved from a single table and I tried the following query
to do so:
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN M.Id ELSE '-' END) "Jan",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN M.Id ELSE '-' END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);
Unfortunately this doesn't return the expected data, instead it shows the yearly
attendance of a user for each month as follows:
Year - Jan - Feb
2018 - 292 - 292
2019 - 100 - 100
Did I miss something here? Any ideas would be appreciated.

Try this-
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN M.Id ELSE NULL END) "Jan",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN M.Id ELSE NULL END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);
OR-
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN 1 ELSE 0 END) "Jan",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN 1 ELSE 0 END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);

I prefer using SUM() for this. But more importantly, your code is mixing types. EXTRACT() returns a number so the comparison should be to a number. I recommend:
SELECT EXTRACT(YEAR FROM M.DATE) as "YEAR",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = 1 THEN 1 ELSE 0 END) as "Jan",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = 2 THEN 1 ELSE 0 END) as "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND
M.Id = 12345678 -- I am guessing that `id` is also a number
GROUP BY EXTRACT(YEAR FROM M.DATE)
ORDER BY EXTRACT(YEAR FROM M.DATE);
You should be careful mixing types. Conversions can impede the ability of the optimizer to find the best query plan.

Related

Rewrite the query to get output for cross years?

SELECT
sum(case
when "year" = '2016' then "svalue"
ELSE 0
END) as 'sva_2016',
sum(case
when "year" = '2017' then "svalue"
ELSE 0
END) as 'sva_2017',
sum(case
when "year" = '2018' then "svalue"
ELSE 0
END) as 'sva_2018',
sum(case
when "year" = '2019' then "svalue"
ELSE 0
END) as 'sva_2019',
sum(case
when "year" = '2016' then "ltr"
ELSE 0
END) as 'lva_2016',
sum(case
when "year" = '2017' then "ltr"
ELSE 0
END) as 'lva_2017',
sum(case
when "year" = '2018' then "ltr"
ELSE 0
END) as 'lva_2018',
sum(case
when "year" = '2019' then "ltr"
ELSE 0
END) as 'lva_2019',
'Apr 1 - Jan 31' as 'Period',
"code" as 'FACode'
FROM "FCJOIN"
WHERE "code" IN
(
SELECT "fccode"
FROM "fcdetails"
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code"
The above query gives me the correct out put for svalues and ltr for
April 2016- December 2016
April 2017- December 2017
April 2018- December 2018
April 2019- December 2019
Now I want to get the values of svalues and ltrs for the period of
April 2016- January 2017
April 2017- January 2018
April 2018- January 2019
April 2019- January 2020
You may use CAST("year" + '-' + "month" + '-01' AS DATETIME) to compare operations.
Btw. it is good example to use PIVOT operator.
Convert the year/month to a date and use date comparisons:
select f.code,
sum(case when v.dte >= '2016-04-01' and v.dte < '2017-04-01'
then f.svalue else 0
end) as svalue_2016,
. . .
sum(case when v.dte >= '2016-04-01' and v.dte < '2017-04-01'
then f.ltr else 0
end) as ltr_2016,
. . .
from fcjoin f cross apply
(values (datefromparts(f.year, f.month, 1))
) v(dte)
where f.code in (select fd.fccode from fcdetails fd)
group by code;
I removed all the double quotes, because they just complicate the query.

return a zero for month with zero rows using case extract sql

Trying to list last 12 months counting records in each month and want to include months where no record was found to display 0 next to that month name. I tried including another table that would always have at least one record for all 12 months and case extract the month from their but I know I'm doing this wrong. All the research I did, didn't use case extract and I'm looking to keep it if I can.. open to if i cannot.
Current query works and is:
select count(RMA.id) "Number of RMAs", case extract(month from
RMA.RMA_DATE)when 1 then 'January'
when 2 then 'February'
when 3 then 'March'
when 4 then 'April'
when 5 then 'May'
when 6 then 'June'
when 7 then 'July'
when 8 then 'August'
when 9 then 'September'
when 10 then 'October'
when 11 then 'November'
when 12 then 'December'
else 'error'
end, extract(year from RMA.rma_date)
from RMA,
RMA_DETAIL
where RMA.ID = RMA_DETAIL.RMA_ID And
RMA.rma_date >= sysdate - 365 And
RMA_DETAIL.ID <> 3
group by extract(month from RMA.rma_date), extract(year from RMA.rma_date)
order by extract(year from RMA.rma_date), extract(month from RMA.rma_date)
results
SUM Cases
If you're already fine with identifying the months in the query, it might be worth just summing these up. A count can only count what's in the table. If you sum up the instances of appearance, you'll get a sum of 0 where your months don't appear. Consider something like this:
SELECT
SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '1' THEN 1 ELSE 0) AS January
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '2' THEN 1 ELSE 0) AS February
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '3' THEN 1 ELSE 0) AS March
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '4' THEN 1 ELSE 0) AS April
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '5' THEN 1 ELSE 0) AS May
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '6' THEN 1 ELSE 0) AS June
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '7' THEN 1 ELSE 0) AS July
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '8' THEN 1 ELSE 0) AS August
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '9' THEN 1 ELSE 0) AS September
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '10' THEN 1 ELSE 0) AS October
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '11' THEN 1 ELSE 0) AS November
,SUM(CASE WHEN EXTRACT(month from RMA.RMA_DATE) = '12' THEN 1 ELSE 0) AS December
...

how to optimize my oracle sql?

I need count in range two date,this sql is work,bug not better,can you help me?
select dmc.doctor_id,
(
select count(*)
from hele_dct_member_config dmc
WHERE (EXTRACT(YEAR FROM dmc.start_time) = 2016 OR EXTRACT(YEAR FROM dmc.end_time) = 2016) AND dmc.status=1
AND TO_DATE('2016-01-31', 'yyyy-mm-dd') BETWEEN start_time AND end_time
) Jan,
(
select count(*)
from hele_dct_member_config dmc
WHERE (EXTRACT(YEAR FROM dmc.start_time) = 2016 OR EXTRACT(YEAR FROM dmc.end_time) = 2016) AND dmc.status=1
AND TO_DATE('2016-02-28', 'yyyy-mm-dd') BETWEEN start_time AND end_time
) Feb,
.
.
.
from hele_dct_member_config dmc
enter code here
WHERE (EXTRACT(YEAR FROM dmc.start_time) = 2016 OR EXTRACT(YEAR FROM dmc.end_time) = 2016) AND dmc.status=1
grouy by dmc.doctor_id
I need count in range two date,this sql is work,bug not better,can you help me?
Use conditional aggregation:
select dmc.doctor_id,
sum(case when date '2016-01-31' BETWEEN start_time AND end_time then 1 else 0
end) as Jan,
sum(case when date '2016-02-31' BETWEEN start_time AND end_time then 1 else 0
end) as Feb,
.
.
.
from hele_dct_member_config dmc
where (extract(year from dmc.start_time) = 2016 or
extract(year from dmc.end_time) = 2016) AND
dmc.status = 1
group by dmc.doctor_id;
if i want get quarter count ? this is one way
SUM(case when date '2016-01-31' BETWEEN start_time AND end_time then 1 else 0 end) +
SUM(case when date '2016-02-28' BETWEEN start_time AND end_time then 1 else 0 end) +
SUM(case when date '2016-03-31' BETWEEN start_time AND end_time then 1 else 0 end) one

Error with group by statement?

I'm getting the following error when I run this code. please help me out.
SELECT store, COUNT(DISTINCT saledate), CountNov, CountDec, SumNov, SumDec, (SumNov/CountNov) AS NovAvgRvn, (SumDec/CountDec) AS DecAvgRvn FROM
(
SELECT store, saledate,
CASE WHEN SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN amt END) IS NULL THEN 0
ELSE SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN amt END)
END AS SumNov,
CASE WHEN SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN amt END) IS NULL THEN 0
ELSE SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN amt END)
END AS SumDec,
CASE WHEN COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN saledate END) IS NULL THEN 0
ELSE COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN saledate END)
END AS CountNov,
CASE WHEN COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN saledate END) IS NULL THEN 0
ELSE COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN saledate END)
END AS CountDec
FROM trnsact
WHERE stype = 'p'
GROUP BY store, saledate
) AS T1
WHERE CountDec > 0 AND CountNov > 0
GROUP BY store
ORDER BY store;
Error:
Error Code - 3504
Error Message - [Teradata Database] [TeraJDBC 15.10.00.05] [Error 3504] [SQLState HY000] Selected non-aggregate values must be part of the associated group.
Why are you using a nested query for this?
SELECT store, COUNT(DISTINCT saledate),
SUM(CASE EXTRACT(MONTH FROM saledate) WHEN 11 THEN amt ELSE 0 END) as SumNov,
SUM(CASE EXTRACT(MONTH FROM saledate) WHEN 11 THEN amt ELSE 0 END) as SumDec,
COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN 11 THEN saledate END) as CountNov,
COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN 12 THEN saledate END) as CountDec
FROM trnsact
WHERE stype = 'p'
GROUP BY store;
Notes:
COUNT() never returns NULL so there is no need for the CASE at all.
With an ELSE clause, the SUM() doesn't return NULL either (there would have to be no rows matching for the SUM() to return NULL, and with no matching rows in the group, the group wouldn't exist).
EXTRACT() returns a number, so compare to a number.
Anything that is in your select statement which is not an aggregate like SUM, AVG etc. need to be included in your group by clause if you have a group by clause
Try this hope it helps:
SELECT store, COUNT(DISTINCT saledate), CountNov, CountDec, SumNov, SumDec, (SumNov/CountNov) AS NovAvgRvn, (SumDec/CountDec) AS DecAvgRvn FROM
(
SELECT store, saledate,
CASE WHEN
SUM(CASE EXTRACT(MONTH FROM saledate)
WHEN '11' THEN amt END) IS NULL THEN 0
ELSE SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN amt END)
END AS SumNov,
CASE WHEN SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN amt END) IS NULL THEN 0
ELSE SUM(CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN amt END)
END AS SumDec,
CASE WHEN COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN saledate END) IS NULL THEN 0
ELSE COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '11' THEN saledate END)
END AS CountNov,
CASE WHEN COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN saledate END) IS NULL THEN 0
ELSE COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN '12' THEN saledate END)
END AS CountDec
FROM trnsact
WHERE stype = 'p'
GROUP BY store, saledate, SumNov, SumDec, CountNov, CountDec
) AS T1
WHERE CountDec > 0 AND CountNov > 0
GROUP BY store, saledate, CountNov, CountDec, SumNov, SumDec, NovAvgRvn, DecAvgRvn
ORDER BY store;
The GROUP BY in the Derived Table is not doing aggregation on a month level, thus the COUNT(DISTINCT saledate)will be 1. You shouldn't use strings for numeric data (result of EXTRACT). You don't need the CASE(SUM) because COUNT never returns a NULL (you might use COALESCE instead):
I assume you want a query like this instead:
SELECT store,
-- if you only need the dates from Nov & Dec you can simply do
-- CountNov + CountDec instead
COUNT(DISTINCT saledate),
SUM(CASE EXTRACT(MONTH FROM saledate) WHEN 11 THEN amt ELSE 0 END) AS SumNov,
SUM(CASE EXTRACT(MONTH FROM saledate) WHEN 12 THEN amt ELSE 0 END) AS SumDec,
COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN 11 THEN saledate END) AS CountNov,
COUNT(DISTINCT CASE EXTRACT(MONTH FROM saledate) WHEN 12 THEN saledate END) AS CountDec,
(SumNov/CountNov) AS NovAvgRvn,
(SumDec/CountDec) AS DecAvgRvn
FROM trnsact
WHERE stype = 'p'
-- don't you need a condition to filter for a specific year/month?
AND EXTRACT(MONTH FROM saledate) IN (11,12)
GROUP BY store
ORDER BY store;

Re-Ordering the Months By Federal Fiscal Year

When running the following query I am trying to find a way to display the returned months by federal fiscal year instead of normal sequential value.
(ie I want to display months in the following order Oct, Nov, Dec, Jan, Feb, Mar, Apr, May Jun, Jul, Aug, Sept instead of Jan thru Dec.) Thanks
select wrkgrp,
sum (case when extract(month from reportdate) = 1 then 1 else 0 end) as January,
sum (case when extract(month from reportdate) = 2 then 1 else 0 end) as February,
sum (case when extract(month from reportdate) = 3 then 1 else 0 end) as March,
sum (case when extract(month from reportdate) = 4 then 1 else 0 end) as April,
sum (case when extract(month from reportdate) = 5 then 1 else 0 end) as May,
sum (case when extract(month from reportdate) = 6 then 1 else 0 end) as June,
sum (case when extract(month from reportdate) = 7 then 1 else 0 end) as July,
sum (case when extract(month from reportdate) = 8 then 1 else 0 end) as August,
sum (case when extract(month from reportdate) = 9 then 1 else 0 end) as September,
sum (case when extract(month from reportdate) = 10 then 1 else 0 end) as October,
sum (case when extract(month from reportdate) = 11 then 1 else 0 end) as November,
sum (case when extract(month from reportdate) = 12 then 1 else 0 end) as December,
from workorder
where reportdate between to_date ('2014-10-01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and to_date ('2015-09-30 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and wrkgrp = 'PublicWorks'
group by 'wrkgrp;'
The fields will display in your results (horizontally) in the order you list them in your select statement. Structure your statement with Oct listed first like this:
select wrkgrp,
sum (case when extract(month from reportdate) = 10 then 1 else 0 end) as October,
sum (case when extract(month from reportdate) = 11 then 1 else 0 end) as November,
sum (case when extract(month from reportdate) = 12 then 1 else 0 end) as December,
sum (case when extract(month from reportdate) = 1 then 1 else 0 end) as January,
sum (case when extract(month from reportdate) = 2 then 1 else 0 end) as February,
sum (case when extract(month from reportdate) = 3 then 1 else 0 end) as March,
sum (case when extract(month from reportdate) = 4 then 1 else 0 end) as April,
sum (case when extract(month from reportdate) = 5 then 1 else 0 end) as May,
sum (case when extract(month from reportdate) = 6 then 1 else 0 end) as June,
sum (case when extract(month from reportdate) = 7 then 1 else 0 end) as July,
sum (case when extract(month from reportdate) = 8 then 1 else 0 end) as August,
sum (case when extract(month from reportdate) = 9 then 1 else 0 end) as September
from workorder
where reportdate between to_date ('2014-10-01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') ad to_date ('2015-09-30 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
wrkgrp = 'PublicWorks'
group by 'wrkgrp;'
Add case statements in your order by clause to get the desired sort.
ORDER BY
CASE WHEN extract(month from reportdate) = 10 THEN 1
CASE WHEN extract(month from reportdate) = 11 THEN 2
ASC