This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 8 years ago.
I have a query that produces results like the following:
Company Member Account Date Check-ins
================================================================
Acme, Inc. Amanda Smith 4145886 7/3/2014 1
Acme, Inc. Amanda Smith 4145886 7/9/2014 1
Acme, Inc. Amanda Smith 4145886 7/23/2014 1
Acme, Inc. Gladys Jones 800138618 7/5/2014 1
Acme, Inc. Joe Ortega 800123972 7/15/2014 1
Acme, Inc. Joe Ortega 800123972 7/29/2014 1
Here is the query:
Select
com.CompanyName as [Company],
p.FirstName + ' ' + p.LastName as [Member],
a.AccountID as [Account],
CAST(mc.CheckInDate AS Date) [Date],
count(*) AS [Check-ins]
from
gym.Person p
join
gym.AccountPeople ap on p.PersonID = ap.PersonID
join
gym.Account a on a.AccountID = ap.AccountID
join
gym.MembershipStatus ms on a.MembershipStatusID = ms.MembershipStatusID
join
gym.Company com on a.CompanyID = com.CompanyID
join
gym.MemberCheckin mc on mc.PersonID = p.PersonID
where
mc.CheckInDate > '2014-7-1'
and mc.CheckInDate < DATEADD(dd, 1, CAST('2014-7-31' AS Date))
GROUP BY
com.CompanyName, a.AccountID,
p.FirstName + ' ' + p.LastName, CAST(mc.CheckInDate AS Date)
order by
com.CompanyName, p.FirstName + ' ' + p.LastName
I'm puzzling over how to get this a little differently. Notice how Amanda checked in 3 times in July, on the 3rd, the 9th, and the 23rd. I need the results to show the check-in count across every day of the month. So in place of the "Date" column I need 31 columns (for each possible day of the longest possible month), like so:
1 2 3 4 5 6 7 8 9 10 .....
==============================================
0 0 1 0 0 0 0 0 1 0 ......
Notice the "check-in" count under 3 and 9, for July 3rd and July 9th. How can I build the query to produce results like that?
Ugly answer...but you should be able to create 31 case statements to get this to work. In your select (at the end works) include:
sum(case when day([date]) = 1 then 1 else 0 end) as day1,
sum(case when day([date]) = 2 then 1 else 0 end) as day2,
sum(case when day([date]) = 3 then 1 else 0 end) as day3,
sum(case when day([date]) = 4 then 1 else 0 end) as day4,
etc
sum(case when day([date]) = 31 then 1 else 0 end) as day31
Would be curious if there is a better answer, but it should function for you. They are sum columns, so the existing group bys should function fine.
Related
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.
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);
This is my query:
SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
ORDER BY MonthNumber
Which produces result set as:
Name Month ServiceDeliveryTime MonthNumber
----------------------------------------------------------------------------
mb January 52 1
MikeCasey January 10 1
MikeCasey February 4 2
PrecisionCareSupport February 0 2
MikeCasey March 4 3
PrecisionCareSupport March 0 3
MikeCasey April 8 4
PrecisionCareSupport April 0 4
MikeCasey May 16 5
MikeCasey July 4 7
PrecisionCareSupport July 1 7
PrecisionCareSupport August 0 8
MikeCasey September 10 9
MikeCasey October 12 10
I am generating a chart and would like to generate series for that chart but the series should be formed in a way that each series label must have all the tick values(zero if missing respective month). In Simple words,I want resultset as:
Name Month ServiceDeliveryTime MonthNumber
----------------------------------------------------------------------------
mb January 52 1
mb February 0 2
mb March 0 3
mb April 0 4
- - 0 5
Upto December then series will continue for Client MikeCasey upto December and so on...for all the series Labels.If any of the tick is missing for that client there will be value zero for that month.
How Can I produce this result set ? I want some uniform solution because there can be number of such queries for different charts.
Mr Shaw, try this
;WITH
(SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
) AS mytable
SELECT
myTableName.Name
,mytableMonth.Month
,ISNULL(mytable.ServiceDeliveryTime,0)
,mutableMonth.MonthNumber
FROM
(SELECT DISTINCT Name from mytable) mytableName
CROSS JOIN (SELECT DISTINCT Month,MonthNumber FROM mytable) mytableMonth
LEFT INNER JOIN mytable ON mytableName.Name = mytable.Name AND mytableMonth.Month = mytable.Month AND mytableMonthNumber = mytable.MonthNumber
ORDER BY mytableName.Name, mytableMonth.MonthNumber
I have taken all distinct months and names from your data and done a cross join.
;WITH mytable(Name,Month,ServiceDeliveryTime,MonthNumber) AS
(
SELECT STAFF.stf_first_name + '' + STAFF.stf_last_name As Name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date) As Month,
SUM(case when RES_HAB_DATA.reshabdata_duration > 0
then (RES_HAB_DATA.reshabdata_duration/15) else 0 end) As ServiceDeliveryTime,
MONTH(RES_HAB_DATA.reshabdata_data_date) As MonthNumber
FROM RES_HAB_DATA
JOIN RES_HAB ON RES_HAB_DATA.reshab_id = RES_HAB.reshab_id
JOIN STAFF ON RES_HAB_DATA.staff_id = STAFF.stf_id
WHERE RES_HAB.serv_id = 30
AND RES_HAB_DATA.reshabdata_data_date >= '1/1/2015'
GROUP BY STAFF.stf_last_name,
STAFF.stf_first_name,
DATENAME(month,RES_HAB_DATA.reshabdata_data_date),
MONTH(RES_HAB_DATA.reshabdata_data_date)
)
SELECT
myTableName.Name
,mytableMonth.Month_Name
,ISNULL(mytable.ServiceDeliveryTime,0) as ServiceDeliveryTime
,mytableMonth.id
FROM
(SELECT DISTINCT Name from mytable) mytableName
CROSS JOIN (SELECT DISTINCT Month_Name,id FROM MyMonths) mytableMonth
LEFT JOIN mytable ON mytableName.Name = mytable.Name AND mytableMonth.Month_Name = mytable.Month AND mytable.MonthNumber = mytable.MonthNumber
ORDER BY mytableName.Name, mytableMonth.id
MyMonths table is already created table with id as MonthNumber and Month_Name as Month.
Cheers!
I do have a table license_Usage where which works like a log of the usage of licenses in a day
ID User license date
1 1 A 22/1/2015
2 1 A 23/1/2015
3 1 B 23/1/2015
4 1 A 24/1/2015
5 2 A 22/2/2015
6 2 A 23/2/2015
7 1 B 23/2/2015
Where I want to Count how many licenses a user used in a month, the result should look like:
User Jan Feb
1 2 1 ...
2 0 2
How can I manage to do that???
You need a PIVOT or cross tab query. e.g.
SELECT [User],
COUNT(CASE WHEN Month = 1 THEN 1 END) AS Jan,
COUNT(CASE WHEN Month = 2 THEN 1 END) AS Feb,
COUNT(CASE WHEN Month = 3 THEN 1 END) AS Mar
/*TODO - Fill in other 9 months using above pattern*/
FROM [license]
CROSS APPLY (SELECT MONTH([date])) AS CA(Month)
WHERE [date] >= '20150101'
AND [date] < '20160101'
AND [license] = 'A'
GROUP BY [User]
SQL Fiddle
The query below returns problems created for a developer in last 12 months. The query below works fine, but I wanted this to return 0 when there is no match.
SELECT
count(1) as count,
MONTH(pro.[DATE_CREATED]) AS MONTHNAME,
YEAR(pro.[DATE_CREATED]) AS YEARNAME ,
problemStatus.TypeName
FROM
[TestDB].[dbo].PROBLEMS AS pro
LEFT JOIN
[TestDB].[dbo].PROBLEMSTATUS AS problemStatus ON problemStatus.ID = pro.ID_STATUS
LEFT JOIN
[TestDB].[dbo].CUSTOMER AS cust ON pro.ID = cust.ID
WHERE
pro.ID = 1010101010
AND pro.[DATE_CREATED] >= DATEADD(m, -6, current_timestamp)
GROUP BY
MONTH(pro.[DATE_CREATED]),
YEAR(pro.[DATE_CREATED]),
problemStatus.type
ORDER BY
MONTH(pro.[DATE_CREATED]) DESC
Right now the query returns,
Count Month Year Status
1 12 2013 Fixed
1 11 2013 Fixed
1 9 2013 Fixed
1 8 2013 Fixed
1 2 2014 Fixed
1 1 2014 Opened
1 1 2014 Fixed
I want this to return
Count Month Year Status
1 12 2013 Fixed
0 12 2013 Opened
1 11 2013 Fixed
0 11 2013 Opened
1 9 2013 Fixed
0 9 2013 Opened
1 8 2013 Fixed
0 8 2013 Opened
1 2 2014 Fixed
0 2 2014 Opened
1 1 2014 Opened
1 1 2014 Fixed
If you have data in the table for all months, but just not for that ID, then try this:
SELECT sum(case when pro.ID = 1010101010 then 1 else 0 end) as count,
MONTH(pro.[DATE_CREATED]) AS MONTHNAME,
YEAR(pro.[DATE_CREATED]) AS YEARNAME ,
coalesce(max(case when pro.ID = 1010101010 then problemStatus.TypeName end), 'Opened') as problemStatus
FROM [TestDB].[dbo].PROBLEMS AS pro
left JOIN [TestDB].[dbo].PROBLEMSTATUS AS problemStatus
ON problemStatus.ID = pro.ID_STATUS
left JOIN [TestDB].[dbo].CUSTOMER AS cust
ON pro.ID = cust.ID
WHERE pro.[DATE_CREATED] >= DATEADD(m, -6, current_timestamp)
GROUP BY MONTH(pro.[DATE_CREATED]), YEAR(pro.[DATE_CREATED]) , problemStatus.type
ORDER BY MONTH(pro.[DATE_CREATED]) DESC;