Group by datepart and find total count of individual values of each record - sql

This is table structure;
ID Score Valid CreatedDate
1 A 1 2018-02-19 23:33:10.297
2 C 0 2018-02-19 23:32:40.700
3 B 1 2018-02-19 23:32:30.247
4 A 1 2018-02-19 23:31:37.153
5 B 0 2018-02-19 23:25:08.667
...
I need to find total number of each score and valid in each month
I mean final result should be like
Month A B C D E Valid(1) NotValid(0)
January 123 343 1021 98 12 1287 480
February 516 421 321 441 421 987 672
...
This is what I tried;
SELECT DATEPART(year, CreatedDate) as Ay,
(select count(*) from TableResults where Score='A') as 'A',
(select count(*) from TableResults where Score='B') as 'B',
...
FROM TableResults
group by DATEPART(MONTH, CreatedDate)
but couldn't figure how to calculate all occurrence of scores on each month.

Use conditional aggregation.
SELECT DATEPART(year, CreatedDate) as YR
, DATEPART(month, CreatedDate) MO
, sum(Case when score = 'A' then 1 else 0 end) as A
, sum(Case when score = 'B' then 1 else 0 end) as B
, sum(Case when score = 'C' then 1 else 0 end) as C
, sum(Case when score = 'D' then 1 else 0 end) as D
, sum(Case when score = 'E' then 1 else 0 end) as E
, sum(case when valid = 1 then 1 else 0 end) as Valid
, sum(case when valid = 0 then 1 else 0 end) as NotValid
FROM TableResults
GROUP BY DATEPART(MONTH, CreatedDate), DATEPART(year, CreatedDate)
I'm not a big fan of queries in the select; I find they tend to cause performance problems in the long run. Since we're aggregating here I just applied the conditional logic to all the columns.

Related

Count average with multiple conditions

I'm trying to create a query which allows to categorize the average percentage for specific data per month.
Here's how my dataset presents itself:
Date
Name
Group
Percent
2022-01-21
name1
gr1
5.2
2022-01-22
name1
gr1
6.1
2022-01-26
name1
gr1
4.9
2022-02-01
name1
gr1
3.2
2022-02-03
name1
gr1
8.1
2022-01-22
name2
gr1
36.1
2022-01-25
name2
gr1
32.1
2022-02-10
name2
gr1
35.8
...
...
...
...
And here's what I want to obtain with my query (based on what I showed of the table):
Month
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
01
1
1
0
0
02
1
1
0
0
...
...
...
...
...
The result needs to:
Be ordered by month
Have the average use for each name counted and categorized
So far I know how to get the average of the Percent value per Name:
SELECT Name,
AVG(Percent)
from `table`
where Group = 'gr1'
group by Name
and how to count iterations of Percent in the categories created for the query:
SELECT EXTRACT(MONTH FROM Date) as Month,
COUNT(CASE WHEN Percent <= 25 AND Group = 'gr1' THEN Name END) `_25`,
COUNT(CASE WHEN Percent > 25 AND Percent <= 50 AND Group = 'gr1' THEN Name END) `_50`,
COUNT(CASE WHEN Percent > 50 AND Percent <= 75 AND Group = 'gr1' THEN Name END) `_75`,
COUNT(CASE WHEN Percent > 75 AND Percent <= 100 AND Group = 'gr1' THEN Name END) `_100`,
FROM `table`
GROUP BY Month
ORDER BY Month
but this counts all iterations of every name where I want the average of those values.
I've been struggling to figure out how to combine the two queries or to create a new one that answers my need.
I'm working with the BigQuery service from Google Cloud
This query produces the needed result, based on your example. So basically this combines your 2 queries using subquery, where the subquery is responsible to calculate AVG grouped by Name, Month and Group, and the outer query is for COUNT and "categorization"
SELECT
Month,
COUNT(CASE
WHEN avg <= 25 THEN Name
END) AS _25,
COUNT(CASE
WHEN avg > 25
AND avg <= 50 THEN Name
END) AS _50,
COUNT(CASE
WHEN avg > 50
AND avg <= 75 THEN Name
END) AS _75,
COUNT(CASE
WHEN avg > 75
AND avg <= 100 THEN Name
END) AS _100
FROM
(
SELECT
EXTRACT(MONTH from Date) AS Month,
Name,
AVG(Percent) AS avg
FROM
table1
GROUP BY Month, Name, Group
HAVING Group = 'gr1'
) AS namegr
GROUP BY Month
This is the result:
Month
_25
_50
_75
_100
1
1
1
0
0
2
1
1
0
0
See also Fiddle (BUT on MySql) - http://sqlfiddle.com/#!9/16c5882/9
You can use this query to Group By Month and each Name
SELECT CONCAT(EXTRACT(MONTH FROM Date), ', ', Name) AS DateAndName,
CASE
WHEN AVG(Percent) <= 25 THEN '1'
ELSE '0'
END AS '<=25%',
CASE
WHEN AVG(Percent) > 25 AND AVG(Percent) <= 50 THEN '1'
ELSE '0'
END AS '25<_<=50%',
CASE
WHEN AVG(Percent) > 50 AND AVG(Percent) <= 75 THEN '1'
ELSE '0'
END AS '50<_<=75%',
CASE
WHEN AVG(Percent) > 75 AND AVG(Percent) <= 100 THEN '1'
ELSE '0'
END AS '75<_<=100%'
from DataTable /*change to your table name*/
group by EXTRACT(MONTH FROM Date), Name
order by DateAndName
It gives the following result:
DateAndName
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
1, name1
1
0
0
0
1, name2
0
1
0
0
2, name1
1
0
0
0
2, name2
0
1
0
0

How to count records by store, day wise and in 2 hours range period with pivot table format?

I have multiple stores records with user's punch records.
I would like to create a report for each store' day-wise which 2 hours have how many employees was working?
Clock In ID Last Name First Name In time Out time
912 Bedolla Jorge 1/1/2021 7:29 1/1/2021 11:31
912 Romero Gabriel 1/1/2021 10:55 1/1/2021 14:07
912 Bedolla Jorge 1/1/2021 12:00 1/1/2021 16:07
912 Zaragoza Daniel 1/1/2021 13:06 1/1/2021 14:57
912 Thaxton Christopher 1/1/2021 14:01 1/1/2021 16:57
912 Jones Elena 1/1/2021 14:01 1/1/2021 16:35
912 Zaragoza Daniel 1/1/2021 15:12 1/1/2021 17:09
912 Jones Elena 1/1/2021 16:45 1/1/2021 18:05
912 Smith Kirsten 1/1/2021 17:30 1/1/2021 20:01
912 Zaragoza Daniel 1/1/2021 17:41 1/1/2021 21:49
Looking for a result something like below. (below result data is incorrect)
store ForDate 0-2 2-4 4-6 6-8 8-10 10-12 12-14 14-16 16-18 18-20 20-22 22-0
912 2021-01-01 0 0 0 1 0 1 2 3 3 2 3 0
912 2021-01-02 0 0 2 1 2 3 2 4 2 3 3 0
912 2021-01-03 0 0 1 1 2 2 2 2 3 0 2 0
912 2021-01-04 0 0 2 0 2 1 2 2 3 3 1 0
912 2021-01-05 0 0 2 1 1 3 4 4 2 2 1 0
912 2021-01-06 0 0 2 0 2 1 2 3 3 2 3 0
912 2021-01-07 0 0 2 1 2 1 3 4 2 2 0 0
912 2021-01-08 0 0 2 2 2 1 3 2 1 2 1 0
912 2021-01-09 0 0 1 1 0 3 1 3 2 2 3 0
912 2021-01-10 0 0 2 2 1 2 2 1 1 2 2 0
I tried to solve with below query but it's wrong and stil it's just inTime but outTime is pending.
SELECT TOP 10 store, ForDate,
ISNULL([0], 0) + ISNULL([1], 0) AS [0-1],
ISNULL([2], 0) + ISNULL([3], 0) AS [2-3],
ISNULL([4], 0) + ISNULL([5], 0) AS [4-5],
ISNULL([6], 0) + ISNULL([7], 0) AS [6-7],
ISNULL([8], 0) + ISNULL([9], 0) AS [8-9],
ISNULL([10], 0) + ISNULL([11], 0) AS [10-11],
ISNULL([12], 0) + ISNULL([13], 0) AS [12-13],
ISNULL([14], 0) + ISNULL([15], 0) AS [14-15],
ISNULL([16], 0) + ISNULL([17], 0) AS [16-17],
ISNULL([18], 0) + ISNULL([19], 0) AS [18-19],
ISNULL([20], 0) + ISNULL([21], 0) AS [20-21],
ISNULL([22], 0) + ISNULL([23], 0) AS [22-23]
FROM (
select *
from
(
select store, CAST(InTime as date) AS ForDate, DATEPART(hour,InTime) AS OnHour, COUNT(*) AS Totals
from Punches
GROUP BY store, CAST(InTime as date),
DATEPART(hour,InTime)
) src
pivot
(
sum(Totals)
for OnHour in ([0],[1], [2], [3],[4], [5], [6],[7],[8], [9], [10],[11], [12], [13],[14], [15], [16],[17],[18], [19],[20],[21], [22], [23])
) piv
) t1
order by store, ForDate
Here is SQL Fiddle with data.
https://www.db-fiddle.com/f/jo4atDmmj8cshyK1CWWo7x/2
That is insane but worth trying
SELECT storeid, ForDate,
ISNULL([0], 0) + ISNULL([1], 0) AS [0-1],
ISNULL([2], 0) + ISNULL([3], 0) AS [2-3],
ISNULL([4], 0) + ISNULL([5], 0) AS [4-5],
ISNULL([6], 0) + ISNULL([7], 0) AS [6-7],
ISNULL([8], 0) + ISNULL([9], 0) AS [8-9],
ISNULL([10], 0) + ISNULL([11], 0) AS [10-11],
ISNULL([12], 0) + ISNULL([13], 0) AS [12-13],
ISNULL([14], 0) + ISNULL([15], 0) AS [14-15],
ISNULL([16], 0) + ISNULL([17], 0) AS [16-17],
ISNULL([18], 0) + ISNULL([19], 0) AS [18-19],
ISNULL([20], 0) + ISNULL([21], 0) AS [20-21],
ISNULL([22], 0) + ISNULL([23], 0) AS [22-23]
FROM (
select *
from
(
SELECT [Dates].StoreId, [Dates].ForDate, Hours.hour OnHour, COUNT(*) Totals FROM (
SELECT storeId, CAST(InTime as date) AS ForDate FROM Punches
UNION
SELECT storeId, CAST(OutTime AS date) AS ForDate FROM Punches
) [Dates] JOIN (
SELECT * FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)) hours([hour])
) [Hours] ON 1=1
JOIN
(
SELECT * FROM dbo.Punches
) p
ON p.StoreId = [Dates].StoreId
AND (DATEADD(HOUR, [Hours].[hour], CAST([Dates].ForDate AS DATETIME)) BETWEEN CAST(p.InTime AS DATETIME) AND CAST(p.Outtime AS DATETIME))
GROUP BY [Dates].StoreId, Dates.ForDate, [hour]
) src
pivot
(
sum(Totals)
for OnHour in ([0],[1], [2], [3],[4], [5], [6],[7],[8], [9], [10],[11], [12], [13],[14], [15], [16],[17],[18], [19],[20],[21], [22], [23])
) piv
) t1
order by storeid, ForDate
Let's go a bit deeper:
I generated all possible dates by this part:
SELECT storeId, CAST(InTime as date) AS ForDate FROM Punches
UNION
SELECT storeId, CAST(OutTime AS date) AS ForDate FROM Punches
And all possible hours by doing this:
SELECT * FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)) hours([hour])
Then I joined them to find all possible date-hours.
After that, I just joined them with punches and counted the punch if the generated date-hour is between inTime and OutTime by adding this condition:
(DATEADD(HOUR, [Hours].[hour], CAST([Dates].ForDate AS DATETIME)) BETWEEN CAST(p.InTime AS DATETIME) AND CAST(p.Outtime AS DATETIME))
The rest is exactly the same as your code
You can use simple CASE statement to get what you so far try-
SELECT StoreId, CAST(InTime as Date) as ForDate,
SUM(CASE WHEN DATEPART(hour,InTime) in (0,1) THEN 1 ELSE 0 END) AS [0-1],
SUM(CASE WHEN DATEPART(hour,InTime) in (2,3) THEN 1 ELSE 0 END) AS [2-3],
SUM(CASE WHEN DATEPART(hour,InTime) in (4,5) THEN 1 ELSE 0 END) AS [4-5],
SUM(CASE WHEN DATEPART(hour,InTime) in (6,7) THEN 1 ELSE 0 END) AS [6-7],
SUM(CASE WHEN DATEPART(hour,InTime) in (8,9) THEN 1 ELSE 0 END) AS [8-9],
SUM(CASE WHEN DATEPART(hour,InTime) in (10,11) THEN 1 ELSE 0 END) AS [10-11],
SUM(CASE WHEN DATEPART(hour,InTime) in (12,13) THEN 1 ELSE 0 END) AS [12-13],
SUM(CASE WHEN DATEPART(hour,InTime) in (14,15) THEN 1 ELSE 0 END) AS [14-15],
SUM(CASE WHEN DATEPART(hour,InTime) in (16,17) THEN 1 ELSE 0 END) AS [16-17],
SUM(CASE WHEN DATEPART(hour,InTime) in (18,19) THEN 1 ELSE 0 END) AS [18-19],
SUM(CASE WHEN DATEPART(hour,InTime) in (20,21) THEN 1 ELSE 0 END) AS [20-21],
SUM(CASE WHEN DATEPART(hour,InTime) in (22,23) THEN 1 ELSE 0 END) AS [22-23]
FROM Punches
GROUP BY StoreId, CAST(InTime as Date)
And for your final result use below query:-
Select StoreId,ForDate,
SUM(CASE WHEN [0-2]>0 THEN 1 ELSE 0 END) AS [0-2],
SUM(CASE WHEN [2-4]>0 THEN 1 ELSE 0 END) AS [2-4],
SUM(CASE WHEN [4-6]>0 THEN 1 ELSE 0 END) AS [4-6],
SUM(CASE WHEN [6-8]>0 THEN 1 ELSE 0 END) AS [6-8],
SUM(CASE WHEN [8-10]>0 THEN 1 ELSE 0 END) AS [8-10],
SUM(CASE WHEN [10-12]>0 THEN 1 ELSE 0 END) AS [10-12],
SUM(CASE WHEN [12-14]>0 THEN 1 ELSE 0 END) AS [12-14],
SUM(CASE WHEN [14-16]>0 THEN 1 ELSE 0 END) AS [14-16],
SUM(CASE WHEN [16-18]>0 THEN 1 ELSE 0 END) AS [16-18],
SUM(CASE WHEN [18-20]>0 THEN 1 ELSE 0 END) AS [18-20],
SUM(CASE WHEN [20-22]>0 THEN 1 ELSE 0 END) AS [20-22],
SUM(CASE WHEN [22-24]>0 THEN 1 ELSE 0 END) AS [22-24]
from
(SELECT StoreId,FirstName+LastName as Name, CAST(InTime as Date) as ForDate,
SUM(CASE WHEN DATEPART(hour,InTime) in (0,1) OR (DATEPART(hour,InTime)<0 AND DATEPART(hour,OutTime)>=1) THEN 1 ELSE 0 END) AS [0-2],
SUM(CASE WHEN DATEPART(hour,InTime) in (2,3) OR (DATEPART(hour,InTime)<2 AND DATEPART(hour,OutTime)>=2) THEN 1 ELSE 0 END) AS [2-4],
SUM(CASE WHEN DATEPART(hour,InTime) in (4,5) OR (DATEPART(hour,InTime)<4 AND DATEPART(hour,OutTime)>=4) THEN 1 ELSE 0 END) AS [4-6],
SUM(CASE WHEN DATEPART(hour,InTime) in (6,7) OR (DATEPART(hour,InTime)<6 AND DATEPART(hour,OutTime)>=6) THEN 1 ELSE 0 END) AS [6-8],
SUM(CASE WHEN DATEPART(hour,InTime) in (8,9) OR (DATEPART(hour,InTime)<8 AND DATEPART(hour,OutTime)>=8) THEN 1 ELSE 0 END) AS [8-10],
SUM(CASE WHEN DATEPART(hour,InTime) in (10,11) OR (DATEPART(hour,InTime)<10 AND DATEPART(hour,OutTime)>=10) THEN 1 ELSE 0 END) AS [10-12],
SUM(CASE WHEN DATEPART(hour,InTime) in (12,13) OR (DATEPART(hour,InTime)<12 AND DATEPART(hour,OutTime)>=12) THEN 1 ELSE 0 END) AS [12-14],
SUM(CASE WHEN DATEPART(hour,InTime) in (14,15) OR (DATEPART(hour,InTime)<14 AND DATEPART(hour,OutTime)>=14) THEN 1 ELSE 0 END) AS [14-16],
SUM(CASE WHEN DATEPART(hour,InTime) in (16,17) OR (DATEPART(hour,InTime)<16 AND DATEPART(hour,OutTime)>=16) THEN 1 ELSE 0 END) AS [16-18],
SUM(CASE WHEN DATEPART(hour,InTime) in (18,19) OR (DATEPART(hour,InTime)<18 AND DATEPART(hour,OutTime)>=18) THEN 1 ELSE 0 END) AS [18-20],
SUM(CASE WHEN DATEPART(hour,InTime) in (20,21) OR (DATEPART(hour,InTime)<20 AND DATEPART(hour,OutTime)>=20) THEN 1 ELSE 0 END) AS [20-22],
SUM(CASE WHEN DATEPART(hour,InTime) in (22,23) OR (DATEPART(hour,InTime)<22 AND DATEPART(hour,OutTime)>=22) THEN 1 ELSE 0 END) AS [22-24]
FROM Punches
GROUP BY StoreId,FirstName+LastName,CAST(InTime as Date)) detailsQuery
GROUP BY StoreId,ForDate

Multiple SUM in one query with multiple where

I'm trying to write a SQL query that produces a table with summarized values for each year and month.
I have a table that looks something like this:
TABLENAME: TIME
id cID cDate cTime
1 254 2019-10-11 5
2 259 2019-10-13 4
3 268 2020-01-17 6
4 268 2020-01-18 9
5 271 2020-01-21 4
6 267 2020-02-19 8
And another table that looks like this:
TABLENAME: CASE
id name invoice status
254 Acme Yes finish
259 Tex NoFakt finish
268 Rex C Yes *Null*
267 Hydro *Null* open
271 Corp Yes finish
I want to have a query that returns the sum for each month like this:
Year Month RegTime Invoiced ToBeInvoiced
2019 10 5 5 0
2019 11 0 0 0
2019 12 0 0 0
2020 1 19 4 15
2020 2 8 0 8
Explanation of the output:
Year and Month are obvious
RegTime should be the sum of all TIME.cTime WHERE CASE.invoice <> 'NoFakt'
Invoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish'
ToBeInvoiced should be the sum of all TIME.cTIME WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish'
I have tried this query, but with this i need to loop a predefined year and month value in my programming code instead of simply having a sql statement that are doing all the work. ThereĀ“s got to be a simpler way than this...
select (select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice <> 'NoFakt' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS RegTime,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status = 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS Invoiced,
(select sum(cTIME) from TIME inner join CASE on TIME.cID = CASE.id WHERE CASE.invoice = 'Yes' AND CASE.status <> 'finish' AND DATEPART(yy, cDate) = '2019' AND DATEPART(mm, cDate) = '10') AS ToBeInvoiced
Use conditional aggregation :
SELECT YEAR(T.cDate) AS YR, MONTH(T.cDate) AS Mnth,
SUM(CASE WHEN C.invoice <> 'NoFakt' THEN C.cTIME ELSE 0 END) AS RegTime,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status = 'finish' THEN C.cTIME ELSE 0 END) AS Invoiced,
SUM(CASE WHEN C.invoice = 'Yes' AND C.status <> 'finish' THEN C.cTIME ELSE 0 END) AS ToBeInvoiced
FROM TIME T INNER JOIN
CASE C
ON T.cID = C.id
GROUP BY YEAR(T.cDate), MONTH(T.cDate);
Note: Do not use reserved keyword as Object Name.

how to sum two column within single case statement

The query below returns 2 rows, but actually I need only one;
select Datename(month, m.CreatedDate) as [Ay], sum(case when h.Cinsiyet=1 then 1 else 0 end) as [Group1], sum(case when h.Cinsiyet=2 then 1 else 0 end) as [Group2] from Muayene.Muayene m with(nolock)
join Ortak.Hasta h with(nolock) on m.HastaTc = h.HastaTc
group by h.Cinsiyet, Datename(month, m.CreatedDate)
result:
MonthName Group1 Group2
April 4500 0
April 0 9000
Expected Result:
MonthName Group1 Group2
April 4500 9000
I know I can do it wrapping the query with another select statement and Group by month and Sum these results.. But its not efficient and looks dirty code.
How can I make a trick to get expected result without make another sum statement?
FIx the GROUP BY:
select Datename(month, m.CreatedDate) as [Ay],
sum(case when h.Cinsiyet = 1 then 1 else 0 end) as [Group1],
sum(case when h.Cinsiyet = 2 then 1 else 0 end) as [Group2]
from Muayene.Muayene m join
Ortak.Hasta h
on m.HastaTc = h.HastaTc
group by Datename(month, m.CreatedDate);

sql query to subtract columns

I have a table which looks like this :
Item Month Year Sales
Name1 1 2013 333
Name2 2 2013 454
Name3 1 2013 434
I need to write a stored procedure which looks like this :
Item Sales_On_Month(1) Sales_On_Month(2) Sales_On_Month(2)-Sales_On_Month(1) Sales_On_Month(3) Sales_On_Month(3)-Sales_On_Month(2)
Name1 333 334 1 335 1
Name2 454 454 0 654 200
I tried the following query :
I see a lot of nulls in the middle.If you could let me know the modifications to the query or another approach
it would be great :
select (case when [MONTH] = 1 then Sales END) AS Sales_On_Month(1),
(case when [MONTH] = 2 then Sales END) AS Sales_On_Month(2),
(case when [MONTH] = 2 then Sales END) - (case when [MONTH] = 1 then Sales END) AS Sales_On_Month(2)-Sales_On_Month(1) ...............
from ABC;
Use an aggregate, SUM(), MAX(), whatever, andGROUP BY`:
SELECT Item
,SUM(CASE WHEN [MONTH] = 1 THEN Sales END) AS Sales_1
,SUM(CASE WHEN [MONTH] = 2 THEN Sales END) AS Sales_2
,SUM(CASE WHEN [MONTH] = 2 THEN Sales END) - SUM(CASE WHEN [MONTH] = 1 THEN Sales END) AS Sales_On_Month(2)-Sales_On_Month(1)
FROM ABC
GROUP BY Item