SQL Get 12 weeks as columns - sql-server

i need help on the following.
I have the basic query below:
select count(transactions)
from tx
where customer = 'AA'
This gives me a count of all transactions for the relevant client.
What I want is a query that gives me the same output but broken down into the LATEST last 12 weeks (Monday-Sunday is one full week). These values should be presented as 12 columns with the header of each column presented as the last date of the week (ie Sunday's date).
Furthermore the total transactions are split into status- failed and success. I would like the rows of the transactions to be failed and success so the final table would look like this:
25/03/2018 (week 1)| 01/04/2018| ........ |17/06/2018 << (week 12)
Success 100 | 200 | ........ | 150
Failed 3 | 4 | ........ | 6
Any ideas how this can be done?
Thanks you in advance

Returning pivoted data is usually a lot more hassle than it is worth and you should just leave this up to your presentation layer, which will handle your dynamic columns with much more grace. Regardless of the presentation layer you are using (SSRS, Excel, Power BI, etc), you will get the most flexibility by providing it a standard set of unpivoted data:
declare #t table (id int, TransactionDate date, Outcome varchar(8));
insert into #t values
(1,getdate()-1,'Success')
,(2,getdate()-2,'Success')
,(3,getdate()-2,'Success')
,(4,getdate()-3,'Success')
,(5,getdate()-6,'Failed')
,(6,getdate()-6,'Success')
,(7,getdate()-7,'Success')
,(8,getdate()-8,'Success')
,(9,getdate()-8,'Success')
,(10,getdate()-10,'Success')
,(11,getdate()-10,'Failed')
,(12,getdate()-11,'Success')
,(13,getdate()-13,'Success')
;
with w(ws) as(select dateadd(week, datediff(week,0,getdate())-w, 0) -- Monday at the start of the week, minus w.w weeks for all 12
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) as w(w)
)
,d(ws,d) as(select w.ws
,dateadd(day,d.d,w.ws) as d -- Each day that makes up each week for equijoin to Transactions table
from w
cross join (values(0),(1),(2),(3),(4),(5),(6)) as d(d)
)
select d.ws as WeekStart
,t.Outcome
,count(t.TransactionDate) as Transactions
from d
left join #t as t
on d.d = t.TransactionDate
group by d.ws
,t.Outcome
order by d.ws
,t.Outcome;
Output:
+-------------------------+---------+--------------+
| WeekStart | Outcome | Transactions |
+-------------------------+---------+--------------+
| 2018-04-09 00:00:00.000 | NULL | 0 |
| 2018-04-16 00:00:00.000 | NULL | 0 |
| 2018-04-23 00:00:00.000 | NULL | 0 |
| 2018-04-30 00:00:00.000 | NULL | 0 |
| 2018-05-07 00:00:00.000 | NULL | 0 |
| 2018-05-14 00:00:00.000 | NULL | 0 |
| 2018-05-21 00:00:00.000 | NULL | 0 |
| 2018-05-28 00:00:00.000 | NULL | 0 |
| 2018-06-04 00:00:00.000 | NULL | 0 |
| 2018-06-11 00:00:00.000 | NULL | 0 |
| 2018-06-11 00:00:00.000 | Success | 2 |
| 2018-06-18 00:00:00.000 | NULL | 0 |
| 2018-06-18 00:00:00.000 | Failed | 2 |
| 2018-06-18 00:00:00.000 | Success | 5 |
| 2018-06-25 00:00:00.000 | NULL | 0 |
| 2018-06-25 00:00:00.000 | Success | 4 |
+-------------------------+---------+--------------+

Related

SQL Server : new column based on other columns

I want to calculate a new value for the new column based on other columns in T-SQL.
My data is look like this:
Each row represents one person in one day.
The WorkHours is calculated based on the Portion column:
Round(FF.Portion * 7.4, 3) AS WorkHours
I want to calculate a percentage of hours which people not have been at work in relation to the TOTAL workhours for day for each school. For example if 10 people work full hour in one school for one day, it gives 74 working hours and if one person have been sick that day it will give (7,4 % 74 * 100) which is 10% (the WorkHours is calculated based on Portion column)
In your comment you state Peter had 6 hours on 1/1/2017 as "seek" but it was actually 7.4. With that in mind, we can calculate your results as follows:
declare #table table (Name varchar(16), Date date, School char(2), FreedayCode int, Freeday varchar(64), Portion decimal (6,4))
insert into #table
values
('Mike','20170101','AA',-1,'AtWork',1),
('Mike','20170201','AA',1,'Seek',1),
('Ali','20170101','BB',-1,'AtWork',0.94594),
('Ali','20170201','BB',-1,'AtWork',0.94594),
('Sara','20170101','CC',2,'holiday',1),
('Sara','20170201','CC',1,'Seek',1),
('Peter','20170101','AA',1,'Seek',1),
('Peter','20170201','AA',1,'Seek',1),
('Nina','20170101','AA',-1,'AtWork',0.81081),
('Nina','20170201','AA',-1,'AtWork',0.81081)
select
Name
,Date
,School
,FreeDayCode
,Freeday,Portion
,NewColumn = sum(case when Freeday <> 'AtWork' then Round(Portion * 7.4,3) else 0 end) over (partition by Date, School) / sum(Round(Portion * 7.4,3)) over (partition by Date, School)
from
#table
order by
Date
,School
RETURNS
+-------+------------+--------+-------------+---------+---------+-----------+
| Name | Date | School | FreeDayCode | Freeday | Portion | NewColumn |
+-------+------------+--------+-------------+---------+---------+-----------+
| Mike | 2017-01-01 | AA | -1 | AtWork | 1.0000 | 0.355769 |
| Peter | 2017-01-01 | AA | 1 | Seek | 1.0000 | 0.355769 |
| Nina | 2017-01-01 | AA | -1 | AtWork | 0.8108 | 0.355769 |
| Ali | 2017-01-01 | BB | -1 | AtWork | 0.9459 | 0.000000 |
| Sara | 2017-01-01 | CC | 2 | holiday | 1.0000 | 1.000000 |
| Peter | 2017-02-01 | AA | 1 | Seek | 1.0000 | 0.711538 |
| Mike | 2017-02-01 | AA | 1 | Seek | 1.0000 | 0.711538 |
| Nina | 2017-02-01 | AA | -1 | AtWork | 0.8108 | 0.711538 |
| Ali | 2017-02-01 | BB | -1 | AtWork | 0.9459 | 0.000000 |
| Sara | 2017-02-01 | CC | 1 | Seek | 1.0000 | 1.000000 |
+-------+------------+--------+-------------+---------+---------+-----------+

SSRS : How to show all month of a year as X axis of a graph

I'm working on a graph that shows data for a whole year, but as I'm a newbie, I can't figure out how to show all month on the X axis (including those without data)
Here is the SELECT part of my SQL request :
SELECT DISTINCT
AB.Id AS ID,
MONTH(AP.Date) AS Date
Resulting in the following data:
| ID | Date |
|--------|--------|
| 1 | 2 |
| 2 | 3 |
| 3 | 2 |
| 4 | 2 |
| 5 | 3 |
| 6 | 3 |
| 7 | 3 |
|--------|--------|
Currently I'm using =MonthName(Fields!Date.Value)) as category group, resulting in the following graph :
4| X
3| X
2|
1|
0|_________________
February March
What I want to have is something like this :
4| X
3| X
2|
1|
0|______________________________________
January February March April ...
I've found some workaround on the net using a custom table in the database, but I can't in this case, as it is a MS Dynamics project.
Thank you for your time.
You need to return the right data to your chart so that there is something to include on the axis. To do this, you need to generate every single x-axis value and then find the total that relates to it.
In the script below, I am creating a table of dates that represent the start of the month for each month of the current year. It then goes and finds all the relevant values in your table for that month and does a count. This can then be used as your chart dataset with minimal processing on the client side, which will help with report performance.
declare #t table(ID int,DateValue Date)
insert into #t values (1,'20170204'),(2,'20170307'),(3,'20170203'),(4,'20170207'),(5,'20170304'),(6,'20170302'),(7,'20170309');
with d(d) as(select cast(dateadd(mm,n,dateadd(yyyy,datediff(yyyy,0,getdate()),0)) as date) from(values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) n(n))
select d.d
,count(t.ID) as c
from d
left join #t t
on(d.d = dateadd(mm,datediff(mm,0,t.DateValue),0))
group by d.d
order by d.d;
Output:
+------------+---+
| d | c |
+------------+---+
| 2017-01-01 | 0 |
| 2017-02-01 | 3 |
| 2017-03-01 | 4 |
| 2017-04-01 | 0 |
| 2017-05-01 | 0 |
| 2017-06-01 | 0 |
| 2017-07-01 | 0 |
| 2017-08-01 | 0 |
| 2017-09-01 | 0 |
| 2017-10-01 | 0 |
| 2017-11-01 | 0 |
| 2017-12-01 | 0 |
+------------+---+
You can add a right join to your query with all the month and return its column to the output:
SELECT DISTINCT
AB.Id AS ID,
m.n AS Date
right join (select * from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) m(n) ) m
on MONTH(AP.Date)=m.n

Return records based on min data in source and target if conditions satisfied in sql server

Hi I have data in sql server
Table : emp
Empid | deptid | doj | loc | Status|guid
1 | 10 | 2013-09-25 | hyd | 5 |10
1 | 10 | 2014-03-25 | che | 5 |11
1 | 10 | 2014-04-09 | pune | 5 |12
1 | 10 | 2015-01-22 | pune | 5 |13
2 | 20 | 2015-12-13 | beng | 5 |14
2 | 20 | 2014-12-17 | chen | 5 |15
2 | 20 | 2010-10-15 | beng | 4 |16
Table : empref
empid | deptid | startdate | status |guid
1 | 10 | 2013-10-02 | 2 |1
1 | 10 | 2014-04-09 | 2 |2
1 | 10 | 2015-12-09 | 1 |3
1 | 10 | 2015-01-30 | 2 |4
2 | 20 | 2015-12-14 | 2 |2
2 | 20 | 2015-12-15 | 2 |3
Both tables have common columns Empid + deptid
We need to consider emp table status=5 related records compare with empref table status=2
related records and emp table doj <= startdate --empref table and days difference between less than or equal to 30 days
If we find multiple records fall within 30 days in empref table startdate then we need to consider min(startdate) corresponding records
and that records need to be considered as update. Remain status values 4 or 1 no need in the return result set at this time.
If emp table status=5 related records compare with empref table status=2
related records and emp table doj <= startdate --empref table and daysdiffernce between less than or equal 30 days
If we find multiple records fall with in 30days in emp table doj then we need to consider min(doj) corresponding records
and that record needs to be considered as update in the filter column and guid information from empref table.
Remaining records considered as insert records in the filter column and guid information from emptable.
if emp table doj <=startdate--empref table condition not satisfied or
daysdiffernce not between less than or equal 30 days then that records we need to consider insert in the filter column
based on above tables I want output like below
Empid | Deptid | loc | Status | Filter | Doj |guid
1 | 10 | hyd | 5 | Update | 2013-09-25|1
1 | 10 | che | 5 | insert | 2014-03-25|11 ------min(startdate) corresponding record
1 | 10 | pune | 5 | update | 2014-04-09|2 --------mul
1 | 10 | Pune | 5 | update | 2015-01-22|4
2 | 20 | beng | 5 | update | 2015-12-13|2 --------------min(doj) record
2 | 20 | chen | 5 | insert | 2014-12-17|15
2 | 20 | beng | 4 | insert | 2010-10-15|16 -----this record not fall the above conditions
I tried like below
select s1.*
,'Update' as Filter from emp e join empref er
on e.empid=er.empid and
e.deptid=t.deptid
and e.status='5'
and er.status='2' and
e.doj<=er.startdate and datediff(dd,er.startdate,e.doj)*-1<=30
group by er.startdate,
e.empid,e.deptid.e.doj,e.loc
having e.startdate= min(er.startdate)
In the above query not given expected result. Please help me write this query to achieve this task in sql server.
It seems like the query you supplied is very close. Here is what I quickly put together. I haven't tested it against a lot of the possible options.
select e.Empid, er.deptid, e.loc, e.[status],
case when DATEDIFF(DAY, e.doj, er.startdate) <= 0 THEN 'INSERT'
ELSE 'UPDATE' END [DaysOffset],
e.doj
FROM #emp e inner join #empref ER
on e.Empid = er.empid and
e.deptid = er.deptid
where e.[status] = 5 and er.[status] = 2
and e.doj <= er.startdate and
DATEDIFF(DAY, e.doj, er.startdate) <= 30
The CASE statement is where it determines when the record is flagged for INSERT or UPDATE. With the datediff in the WHERE clause, it will only return records that are 30 days or less.

SQL server 2000 pulling count grouped by time

I have a table like below.
Date | Time | connect |
2013-08-23 00:00:00.000 | 05.26.13 | 1 |
2013-08-23 00:00:00.000 | 05.32.11 | 1 |
2013-08-23 00:00:00.000 | 05.26.13 | 1 |
2013-08-23 00:00:00.000 | 06.02.52 | 1 |
2013-08-23 00:00:00.000 | 06.41.09 | 1 |
2013-08-23 00:00:00.000 | 06.43.12 | 1 |
2013-08-23 00:00:00.000 | 06.52.09 | 1 |
2013-08-23 00:00:00.000 | 06.57.39 | 1 |
2013-10-21 00:00:00.000 | 03.58.35 | 1 |
2013-10-21 00:00:00.000 | 04.02.18 | 1 |
2013-10-21 00:00:00.000 | 04.12.02 | 1 |
2013-10-21 00:00:00.000 | 04.41.36 | 1 |
2013-10-21 00:00:00.000 | 11.12.27 | 1 |
2013-10-22 00:00:00.000 | 11.58.35 | 1 |
I want to get the count of connect that fall in each hour, grouped by date.
Count falling between 1:00 to 1:59, 2:00 to 2:59 and so on. The below is model of the output that I require.
Date | Count(between 4.00.00 to 4.59.59) | Count(between 5.00.00 to 5.59.59) | Count(between 6.00.00 to 6.59.59) |Count(between 11.00.00 to 11.59.59) |
2013-08-23 00:00:00.000 | 0 | 3 | 5 | 0 |
2013-10-21 00:00:00.000 | 3 | 1 | 0 | 1 |
2013-10-22 00:00:00.000 | 0 | 0 | 0 | 1 |
You can just use group by with the date time functions if you don't care about missing 0 row counts, but if you are concerned, use the tally table example Jeff mentions in 2nd page of this forum post: http://www.sqlservercentral.com/Forums/Topic288581-8-1.aspx Both examples in this post, but it note it is by half hour, should be easy to convert to hour.
This is what I want.
by Matt Watson
SELECT [Hourly], COUNT(*) as [Count] FROM (SELECT dateadd(hh, datediff(hh, '20010101', [date_created]), '20010101') as [Hourly] FROM table) idat GROUP BY [Hourly]

Sum worked hours

I have a issues table where users can log worked hours and estimate hours that looks like this
id | assignee | task | timespent | original_estimate | date
--------------------------------------------------------------------------
1 | john | design | 2 | 3 | 2013-01-01
2 | john | mockup | 2 | 3 | 2013-01-02
3 | john | design | 2 | 3 | 2013-01-01
4 | rick | mockup | 5 | 4 | 2013-01-04
And I need to sum and group the worked and estimated hours by task and date to get this
assignee | task | total_spent | total_estimate | date
------------------------------------------------------------------
john | design | 4 | 6 | 2013-01-01
john | mockup | 2 | 3 | 2013-01-02
rick | design | 5 | 4 | 2013-01-04
Ok, this is easy, I've already got this:
SELECT assignee, task, SUM(timespent) as total_spent, SUM(original_estimate) AS total_estimate, date FROM issues GROUP BY assignee, task, date
My problem is I need to also show the assignees that did not logged hours on any task that day, I mean:
assignee | task | total_spent | total_estimate | date
------------------------------------------------------------------
john | design | 4 | 6 | 2013-01-01
john | mockup | 2 | 3 | 2013-01-02
rick | design | 5 | 4 | 2013-01-04
pete | design | 0 | 0 | 2013-01-01
pete | mockup | 0 | 0 | 2013-01-02
liz | design | 0 | 0 | 2013-01-04
liz | mockup | 0 | 0 | 2013-01-04
The goal is to draw a chart like this http://jsfiddle.net/uUjst/embedded/result/
You need the Assignees in their own separate table to join from.
SELECT tblAssignee.Name, task, SUM(timespent) as total_spent, SUM(original_estimate) AS total_estimate, date
FROM tblAssignee
LEFT JOIN issue ON issues.assignee = tblAssignee.Name
GROUP BY tblAssignee.Name, task, date
Assuming that you have a user table, but not a tasks or dates table... meaning that we have to derive these values from the values present in issues:
;WITH dates AS (
SELECT DISTINCT date
FROM issues
), tasks AS (
SELECT DISTINCT task
FROM issues
)
SELECT
u.user as assignee,
t.task,
SUM(i.timespent) as total_spent,
SUM(i.original_estimate) AS total_estimate,
d.date
FROM
users u CROSS JOIN
dates d CROSS JOIN
tasks t LEFT OUTER JOIN
issues i ON
i.assignee = u.user
AND i.task = t.task
AND i.date = d.date
GROUP BY u.user, t.task, d.date
SELECT
A.name,
task,
ISNULL(SUM(timespent), 0) as total_spent,
ISNULL(SUM(original_estimate), 0) AS total_estimate,
date
FROM Assignee A
LEFT JOIN issue
ON issues.assignee = A.Name
GROUP BY A.name, task, date

Resources