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
Related
Hi I would like to get data from date for users. I ve got a table with all months but i would like to get how much they earn on month
user
month
money
1
january
10
2
january
1
1
april
100
2
april
1000
1
march
0
2
march
1
And result should be:
user
money_on_april
money_on_march
1
100
0
2
1000
1
3
0
0
Assuming you want a column for every month, or a certain subset of months:
SELECT
user,
SUM(CASE month WHEN 'january' THEN money ELSE 0 END) As money_on_january,
SUM(CASE month WHEN 'february' THEN money ELSE 0 END) As money_on_february,
...
FROM
YourTable
GROUP BY
user
If you only want columns for the months which exist in the table, then you'll need to use dynamic SQL instead.
If you are using MS SQL, Try PIVOT
SELECT * FROM [Your Table]
PIVOT(
SUM([money])
FOR [month] IN ([january],[april],[march])
)pvt
I have a table data as follows
day group category appcount
-----------------------------------------
Fri F27-28 music 4
Fri F27-28 radio 1
Fri F27-28 show 1
Fri F27-28 video 8
Fri F29-32 music 6
Fri F29-32 radio 2
Fri F29-32 video 22
Fri M22- music 1
Fri M22- video 2
Fri M23-26 music 4
Fri M23-26 video 8
Now, i would like to have a result by pivoting Category and Day, as follows.
Age Group music-Fri music-Mon music-Sun music-Tue music-Sat music-Thu music-Wed radio-Fri radio-Mon radio-Sun radio-Tues radio-Sat radio-Thu radio-Wed
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
F27-28 4 16 5 11 17 13 9 1 1 3 2 8 2
F29-32 6 2 6 4 4 4 2 5 2 3 2
F33-42 2 2 3 1 1 3
M22- 1 15 14 10 4 4
M23-26 4 7 5 2 12 14 7
I have tried few queries but could not achieve grouping 2 columns, day and category. Sorry for data format issue. Please help.
Here is my query
SELECT *
FROM (
SELECT
[group],
[day],
category,
appcount as counts
FROM monthly_age_apps
) as s
PIVOT
(
SUM(counts)
FOR [category] IN (video, radio, show, music)
)AS pvt
Thank you, Sathish
I find it simpler to just use conditional aggregation for many pivot queries:
select agegroup,
sum(case when category = 'music' and day = 'Fri' then appcount else 0 end) as music_fri,
sum(case when category = 'music' and day = 'Mon' then appcount else 0 end) as music_mon,
. . .
from
group by agegroup;
For ANSI-Sql you can use conditional aggregation :
SELECT t.group ,
MAX(CASE WHEN t.day = 'Sun' AND t.category = 'music' AND THEN t.appcount) as Sun-Music,
MAX(CASE WHEN t.day = 'Sun' AND t.category = 'radio' AND THEN t.appcount) as Sun-Radio,
MAX(CASE WHEN t.day = 'Mon' AND t.category = 'music' AND THEN t.appcount) as Mon-Music,
MAX(CASE WHEN t.day = 'Mon' AND t.category = 'radio' AND THEN t.appcount) as Mon-Radio,
........
FROM YourTable t
GROUP BY t.group
I have a table in this form:
id year type amount
1 2015 in 10
2 2015 out 5
3 2016 in 20
4 2016 out 1
...
The followin query will give me the sum of the amount of type = 'in' grouped by year:
SELECT year, sum(amount)
FROM table
WHERE type = in
GROUP BY year
How am I going to get the following result?
year sum(in) sum(out) "in-out"
2015 10 5 5
2016 20 1 19
sum(in) is the sum of the 'amount' where type='in'.
Use a CASE statement to handle the values of type.
SELECT year,
SUM(CASE WHEN type = 'in' THEN amount ELSE 0 END) AS sum_in,
SUM(CASE WHEN type = 'out' THEN amount ELSE 0 END) AS sum_out,
SUM(CASE WHEN type = 'in' THEN amount ELSE -amount END) AS in_out
FROM table
GROUP BY year;
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!
Background Info
I have a large table 400M+ rows that changes daily (one days data drops out an a new days data drops in) The table is partitioned on a 'day' field so there are 31 paritions.
Each row in the table has data similar to this:
ID, Postcode, DeliveryPoint, Quantity, Day, Month
1 SN1 1BG A1 6 29 1
2 SN1 1BG A1 1 28 1
3 SN1 1BG A2 2 27 1
4 SN1 1BG A1 3 28 1
5 SN2 1AQ B1 1 29 12
6 SN1 1BG A1 2 26 12
I need to pull out 7 days of data in the format:
Postcode, Deliverypoint, 7dayAverage, Day1,day2,Day3,Day4,Day5,Day6,Day7
SN1 1BG A1 2 0 1 2 1 3 4 0
I can easily extract the data for the 7 day period but need to create a columnar version as shown above.
I have something like this:
select postcode,deliverypoint,
sum (case day when 23 then quantity else 0 end) as day1,
sum (case day when 24 then quantity else 0 end) as day2,
sum(case day when 25 then quantity else 0 end) as day3,
sum(case day when 26 then quantity else 0 end) as day4,
sum(case day when 27 then quantity else 0 end) as day5,
sum(case day when 28 then quantity else 0 end) as day6,
sum(case day when 29 then quantity else 0 end) as day7,
sum(quantity)*1.0/#daysinweek as wkavg
into #allweekdp
from maintable dp with (nolock)
where day in (select day from #days)
group by postcode,deliverypoint
where #days has the day numbers in the 7 day period.
But as you can see, I've hard-coded the day numbers into the query, I want to get them out of my temporary table #days but can't see a way of doing it (an array would be perfect here)
Or a I going about this in completely the wrong way ?
Kind Regards
Steve
If I understand correctly, what I would do is:
Convert the day and month columns into datetime values,
Get the first day of the week and day of the weekday (1-7) for each date, and
Pivot the data and group by the first day of the week
see here: sqlfiddle
As utexaspunk suggested, Pivot might be the way to go. I've never been comfortable with pivot and have preferred to pivot it manually so I control how everything looks, so I'm using a similar solution to how you did your script to solve the issue. No idea how the performance between my way and utexaspunk's will compare.
Declare #Min_Day Integer = Select MIN(day) as Min_Day From #days;
With Day_Coding_CTE as (
Select Distinct day
, day - #Min_Day + 1 as Day_Label
From #days
)
, Non_Columnar_CTE as (
Select dp.postcode
, dp.deliverypoint
, d.day
, c.Day_Label
, SUM(quantity) as Quantity
From maintable dp with (nolock)
Left Outer Join #days d
on dp.day = d.day --It also seems like you'll need more criteria here, but you'll have to figure out what those should be
Left Outer Join Day_Coding_CTE c
on d.day = c.day
)
Select postcode
, deliverypoint
, SUM(Case
When Day_Label = 1
Then Quantity
Else 0
End) as Day1
, SUM(Case
When Day_Label = 2
Then Quantity
Else 0
End) as Day2
, SUM(Case
When Day_Label = 3
Then Quantity
Else 0
End) as Day3
, SUM(Case
When Day_Label = 4
Then Quantity
Else 0
End) as Day4
, SUM(Case
When Day_Label = 5
Then Quantity
Else 0
End) as Day5
, SUM(Case
When Day_Label = 6
Then Quantity
Else 0
End) as Day6
, SUM(Case
When Day_Label = 7
Then Quantity
Else 0
End) as Day7
, SUM(Quantity)/#daysinweek as wkavg
From Non_Columnar_CTE
Group by postcode
deliverypoint