Convert Rows into Columns in Sql query - sql

I am having tough time to figure out this please help me
I have time in/out sql query
I have a table looks like below. there are four columns display time in/out info such as...
Date Day Day TimeStamp CheckType
10/11/2014 Sat 8:30 am in
10/11/2014 Sat 11:30am out
10/11/2014 Sat 1:30pm in
10/11/2014 Sat out
10/12/2014 Sun 9:00am in
10/12/2014 Sun 11:20pm out
10/12/2014 Sun 5:20pm out
10/13/2014 Mon 8:00am in
10/13/2014 Mon 6:10pm in
so whoever checkin or checkout then the record will display the result in order and if someone is supposed to check out but accidently pressed in button then this will display as it is (in) or if someone forget to check out then that space will show blank
I am trying to convert rows into column and display such information in below
Date Day Time Type Time Type Time Type Time Type etc-----
10/11/2014 Sat 8:30am in 11:30am out 1:30pm in
10/12/2014 Sun 9:00am in 11:20am out 1:20pm in 6:20pm in
10/13/2014 Mon 8:00am in 6:10pm out
10/14/2014 Tus 8:20am in
etc
I have tried to use pivot
select Date, Day, [1],[2],[3],[4],[5],[6],[7],[8],[9],[10] etc---
from
(
select Date, Day, Stamptime, CheckTime, userID
from a table
)
pivot
(
max(StampTime)
for stamptime in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10] etc---)
) as PivotTable
can anyone explain how to convert the rows into columns I have spent many days already.

Here's something close to what you're after, making use of XML to get the variable number of columns. As mentioned in my comment above though, I don't recommend this approach.
SQL Fiddle: http://sqlfiddle.com/#!3/e5b325/2
select [Date]
, [Day]
, (
select [TimeStamp] [Time]
, [CheckType] [Type]
from aTable b
where b.[Date] = a.[Date]
order by [TimeStamp], [CheckType]
for xml path ('')
) CheckInAndOutInfo
from aTable a
group by [Date], [Day]
order by [Date]
Output:
DATE DAY CHECKINANDOUTINFO
2014-10-11 Sat <Type>Out</Type><Time>08:30:00</Time><Type>In</Type><Time>11:30:00</Time><Type>Out</Type><Time>13:30:00</Time><Type>In</Type>
2014-10-12 Sun <Time>09:00:00</Time><Type>In</Type><Time>17:20:00</Time><Type>Out</Type><Time>23:20:00</Time><Type>Out</Type>
2014-10-13 Mon <Time>08:00:00</Time><Type>In</Type><Time>18:10:00</Time><Type>In</Type>
Alternatively, if you can guarantee you'll never have more than a certain number of check-ins/outs per day, you could do the following (this assumes no more than 5 per day):
SQL Fiddle: http://sqlfiddle.com/#!3/e5b325/4
select *
from
(
select [Date], [Day]
, 'T' + CAST(ROW_NUMBER() over (partition by [Date] order by [TimeStamp], [CheckType]) as nvarchar) r
, cast([TimeStamp] as nvarchar) pvtVal
from aTable
where [TimeStamp] is not null
union all
select [Date], [Day]
, 'C' + CAST(ROW_NUMBER() over (partition by [Date] order by [TimeStamp], [CheckType]) as nvarchar) r
, cast([CheckType] as nvarchar) pvtVal
from aTable
where [TimeStamp] is not null
) x
pivot
(
min(pvtVal)
for r in ([T1], [C1], [T2], [C2], [T3], [C3], [T4], [C4], [T5], [C5])
) y
order by [Date]
Output:
DATE DAY T1 C1 T2 C2 T3 C3 T4 C4 T5 C5
2014-10-11 Sat 08:30:00.0000000 In 11:30:00.0000000 Out 13:30:00.0000000 In (null) (null) (null) (null)
2014-10-12 Sun 09:00:00.0000000 In 17:20:00.0000000 Out 23:20:00.0000000 Out (null) (null) (null) (null)
2014-10-13 Mon 08:00:00.0000000 In 18:10:00.0000000 In (null) (null) (null) (null) (null) (null)
...Or if you wanted to use dynamic SQL, you could do this:
SQL Fiddle: http://sqlfiddle.com/#!3/e5b325/6
declare #sql nvarchar(max)
select #sql = coalesce(#sql+',','') + QUOTENAME('T' + CAST(x as nvarchar)) + ',' + QUOTENAME('C' + CAST(x as nvarchar))
from
(
select distinct row_number() over (partition by [Date] order by [Date]) x
from aTable
where [TimeStamp] is not null
) y
order by x
set #sql =
'select *
from
(
select [Date], [Day]
, ''T'' + CAST(ROW_NUMBER() over (partition by [Date] order by [TimeStamp], [CheckType]) as nvarchar) r
, cast([TimeStamp] as nvarchar) pvtVal
from aTable
where [TimeStamp] is not null
union all
select [Date], [Day]
, ''C'' + CAST(ROW_NUMBER() over (partition by [Date] order by [TimeStamp], [CheckType]) as nvarchar) r
, cast([CheckType] as nvarchar) pvtVal
from aTable
where [TimeStamp] is not null
) x
pivot
(
min(pvtVal)
for r in (' + #sql + ')
) y
order by [Date]'
exec (#sql)
Output:
DATE DAY T1 C1 T2 C2 T3 C3
2014-10-11 Sat 08:30:00.0000000 In 11:30:00.0000000 Out 13:30:00.0000000 In
2014-10-12 Sun 09:00:00.0000000 In 17:20:00.0000000 Out 23:20:00.0000000 Out
2014-10-13 Mon 08:00:00.0000000 In 18:10:00.0000000 In (null) (null)

Related

Group and expand to new columns using a SQL query?

Having this data:
Name
Date
John
2021-03-01 10:00
Paul
2021-03-01 11:00
Paul
2021-03-01 14:20
John
2021-03-01 15:00
Paul
2021-03-01 17:00
How can I obtain this result (Dates ordered ASC)
Name
Date1
Date2
Date2
John
2021-03-01 10:00
2021-03-01 15:00
NULL
Paul
2021-03-01 11:00
2021-03-01 14:20
2021-03-01 17:00
Thank you.
If you want to make your query dynamic that means no matter how many dates you have for any given name this query will generate that number of columns automatically try below query:
Schema:
create table mytable (Name varchar(50),[Date] Datetime);
insert into mytable values('John' , '2021-03-01 10:00');
insert into mytable values('Paul' , '2021-03-01 11:00');
insert into mytable values('Paul' , '2021-03-01 14:20');
insert into mytable values('John' , '2021-03-01 15:00');
insert into mytable values('Paul' , '2021-03-01 17:00');
Query:
declare #cols as varchar(max), #colsForSelect as varchar(max), #query as varchar(max);
select #colsForSelect=string_agg(concat(quotename(rn),' ', datename),',' )from(
select distinct concat('Date',rn) datename,rn from
(SELECT row_number()over(partition by name order by [date])rn from mytable)t)a
select #cols =string_agg(quotename(rn),',') from (
select distinct rn from
(SELECT row_number()over(partition by name order by [date])rn from mytable)t)a
set #query = 'Select Name, ' + #colsForSelect + ' from
(
SELECT *,row_number()over(partition by name order by [date])rn
from mytable
) x
pivot
(
max([date])
for rn in (' + #cols + ')
) p
group by Name,' + #cols
execute(#query);
Output:
Name
Date1
Date2
Date3
John
2021-03-01 10:00:00.000
2021-03-01 15:00:00.000
null
Paul
2021-03-01 11:00:00.000
2021-03-01 14:20:00.000
2021-03-01 17:00:00.000
db<>fiddle here
Based on Larnu's help, This worked:
WITH RNs AS(
SELECT [Name],
[DateTime],
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY (SELECT NULL)) AS RN
FROM dbo.Punch
WHERE Date = '2016-04-18'
)
SELECT Name,
MAX(CASE RN WHEN 1 THEN [DateTime] END) AS Result1,
MAX(CASE RN WHEN 2 THEN [DateTime] END) AS Result2,
MAX(CASE RN WHEN 3 THEN [DateTime] END) AS Result3,
MAX(CASE RN WHEN 4 THEN [DateTime] END) AS Result4
FROM RNs R
GROUP BY Name
I have tried with Stuff function instead of sting_agg which was introduced in 2017 server. If you are using below 2017 version you can use the below query.
declare #column_name varchar(5000)
declare #col_name varchar(5000)
set #column_name = (select stuff((select ','+'['+cast(rn as varchar(1000))+']' from(select distinct row_number()over(partition by name order by (select null))as rn from mytable)a
for xml path('')), 1,1,''))
set #col_name = (select stuff((select ','+'['+cast(rn as varchar(1000))+']' +' Date'+cast(rn as varchar(1000)) from(select distinct row_number()over(partition by name order by (select null))as rn from mytable)a
for xml path('')), 1,1,''))
exec('select name, '+#col_name +'
from (
select row_number()over(partition by name order by (select null))rn, year([date]) yr, *
from mytable
)a
pivot
(
max([date]) for [rn] in ('+#column_name+' )
)pv')

Sql Pivot on time

Table 1: Daily attendance data:
att_date emp_code emp_name in_time out_time
2018-10-21 9999 Test 2018-10-21 08:00:00.000 2018-10-22 06:00:00.000
Table 2: Trnevents
emp_readr_id DT EVENTID
9999 2018-10-24 07:00:00.000 0
9999 2018-10-24 05:00:00.000 0
9999 2018-10-24 03:00:00.000 0
9999 2018-10-23 21:00:00.000 0
9999 2018-10-23 19:00:00.000 0
9999 2018-10-23 06:00:00.000 0
9999 2018-10-22 06:00:00.000 0
9999 2018-10-21 08:00:00.000 0
I used this query to get all times in between in time and out time ,below query works fine but i try to make in row by using pivot. While using pivot out time shows in next row.
declare #tempProcesstable as table(
[id] [nvarchar](200) NULL,
[time_stamp] datetime NULL,
[AccessType] varchar(3) NULL)
insert into #tempProcesstable
select distinct t1.emp_Reader_id, t1.DT,t1.eventid from daily_attendance_data t2 join trnevents t1
on t1.emp_reader_id=t2.emp_reader_id where (CONVERT(VARCHAR(26), t2.att_Date, 23) >=CONVERT(VARCHAR(26), '2018-10-20', 23)
and CONVERT(VARCHAR(26), t2.att_date, 23) <=CONVERT(VARCHAR(26), '2018-10-21', 23))
and
(t1.DT >=t2.in_time
and t1.DT <=t2.out_time)
-- and t1.emp_reader_id=1000
group by t1.emp_Reader_id,t1.dt,t1.eventid order by t1.emp_reader_id,DT asc
; With CheckIns
As (Select Rowemp_reader_id = Row_Number() Over (Partition by id, Cast(time_stamp As Date) Order By time_stamp),
id, time_stamp,
[Date] = Cast(time_stamp As Date),
[Time] = Cast(time_stamp As Time(0))
From #tempProcesstable)
Select Pvt.id,B.emp_name , [Date], CHECK1, CHECK2,Cast(dateadd(ss,datediff(ss,CHECK1,CHECK2),0) As Time(0)) Total1,
CHECK3, CHECK4,Cast(dateadd(ss,datediff(ss,CHECK3,CHECK4),0) As Time(0)) Total2
From (Select id, [Date], [Time],
CHECKNum = 'CHECK' + Cast(Rowemp_reader_id As varchar(11))
From CheckIns) As P
Pivot (Min([Time])
For CheckNum In (Check1, [Check2], Check3, Check4)
) As Pvt
LEFT OUTER JOIN
dbo.employee AS B ON Pvt.id= B.emp_reader_id
My output:
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 NULL NULL NULL NULL NULL NULL
9999 Test 2018-10-22 06:00:00 NULL NULL NULL NULL NULL NULL
Expected output:
I want all times between in time and out time in night to morning also.
can any one help me to rectify this.
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 06:00:00 NULL NULL NULL NULL NULL
You can try to use ROW_NUMBER() window function make row number by each date.
then use condition aggregate function to do pivot
SELECT emp_readr_id,
emp_name,
[Date],
MAX(CASE WHEN RN = 1 THEN time END) CHECK1,
MAX(CASE WHEN RN = 2 THEN time END) CHECK2,
MAX(CASE WHEN RN = 3 THEN time END) CHECK3,
MAX(CASE WHEN RN = 4 THEN time END) CHECK4
FROM (
SELECT emp_readr_id,
emp_name,
CONVERT(VARCHAR(10),DT,120) 'Date',
ROW_NUMBER() OVER(PARTITION BY CONVERT(VARCHAR(10),DT,120) ORDER BY DT) rn,
CONVERT(VARCHAR(10),DT,108) time
FROM Daily d
JOIN Trnevents t on t.DT between d.in_time and d.out_time
) t1
group by emp_readr_id,
emp_name,
[Date]
sqlifddle

Calculate Employee Timesheet Data

Suppose you have a timeclock table with only a timestamp entry for each timeclock event:
Userid CheckTime
312 2018-05-08 05:52:00
312 2018-05-08 18:06:00
312 2018-05-10 05:55:00
312 2018-05-10 18:00:00
312 2018-05-11 05:58:00
312 2018-05-11 18:00:00
312 2018-05-12 05:35:00
312 2018-05-12 18:00:00
How can I tally the events in SQL Server to show like this?
Day Date In Out Reg OT
Tuesday 5/8/2018 5:52AM 6:06PM 12.00 0.00
Thursday 5/10/2018 5:55AM 6:00PM 12.00 0.00
Friday 5/11/2018 5:58AM 6:00PM 12.00 0.00
Saturday 5/12/2018 5:35AM 6:00PM 12.00 0.42
Plus, we have overnight people who start their shift in one day and carry over to another day.
I'm not sure how to calculate this since it is row based vs column based.
I've tried this...but it doesn't work correctly...
;WITH emp
AS (SELECT [UserID],
[CheckTime],
CAST([CheckTime] AS DATE) AS [Day],
Row_Number()
OVER( PARTITION BY [UserID], CAST([CheckTime] AS DATE)
ORDER BY [UserID], [CheckTime]) AS [RowNumber]
FROM [dbo].[Clock_Data] WHERE CHECKTIME
BETWEEN '2018-05-06' AND '2018-05-13')
SELECT
t1.[UserID],
E.[Last Name]AS [EMPID],
MIN(t1.[CheckTime]) AS [time_in],
MAX(t2.[CheckTime]) AS [time_out],
CAST((SUM(ISNULL(DATEDIFF(ss, t1.[CheckTime],
t2.[CheckTime]) , 0)) / 3600)-1 AS VARCHAR(10)) + '.' +
FROM emp AS t1
LEFT JOIN emp AS t2
ON ( t1.[UserID] = t2.[UserID]
AND t1.[Day] = t2.[Day]
AND t1.[RowNumber] = ( t2.[RowNumber] - 1 )
AND t2.[RowNumber] % 2 = 0
)
INNER JOIN Employees as E on t1.Userid = E.[ID Number]
GROUP BY t1.[UserID], E.[Last Name]
ORDER BY t1.[UserID]
As mentioned in the comments above there are a LOT of complexities in this type of query. Missed/duplicate punches. Daylight saving time. Holidays, weekends. The types of things that might count as O/T for whatever rules you need. But for a nice clean set of data like you have you can do this fairly easily. This is by no means a complete solution because you have a LOT of things to iron out for details. But this should serve as a decent starting point.
declare #Something table
(
Userid int
, CheckTime datetime
)
insert #Something values
(312, '2018-05-08 05:52:00')
, (312, '2018-05-08 18:06:00')
, (312, '2018-05-10 05:55:00')
, (312, '2018-05-10 18:00:00')
, (312, '2018-05-11 05:58:00')
, (312, '2018-05-11 18:00:00')
, (312, '2018-05-12 05:35:00')
, (312, '2018-05-12 18:00:00');
with OrderedResults as
(
select *
, RowNum = ROW_NUMBER() over(partition by Userid order by CheckTime)
from #Something
)
, InPunch as
(
select *
, GroupNum = Row_Number () over(partition by Userid order by RowNum)
from OrderedResults
where RowNum % 2 = 1
)
, OutPunch as
(
select *
, GroupNum = Row_Number () over(partition by Userid order by RowNum)
from OrderedResults
where RowNum % 2 = 0
)
select ip.Userid
, PunchDate = convert(date, ip.CheckTime)
, CheckIn = ip.CheckTime
, CheckOut = op.CheckTime
from InPunch ip
join OutPunch op on op.GroupNum = ip.GroupNum

Find all rows where start date is before a prior end date

Is there a way to pull back all records that have overlapping datetimes based on a user?
For instance;
TableA has the following rows;
TrainerID StartTime EndTime
1234 10-1-2015 08:30 10-1-2015 09:00
1234 10-1-2015 08:45 10-1-2015 09:15
1234 10-1-2015 09:30 10-1-2015 10:00
2345 10-1-2015 08:45 10-1-2015 09:15
2345 10-1-2015 09:30 10-1-2015 10:00
I need a query that can pull ONLY the following record because it's start time is before the previous end time for the trainer (double booked):
1234 10-1-2015 08:45 10-1-2015 09:15
The EXIST code below should give you that answer. The code ensures that the start time of the clashing entry is before the start of the main list entry while the start time of the clash is still after the start time of the mail list entry.
SELECT *
FROM tblTest clashing
WHERE EXISTS
(
SELECT 1
FROM tblTest mainlist
WHERE clashing.trainderid = mainlist.trainderid
AND clashing.starttime < mainlist.endtime
AND clashing.starttime > mainlist.starttime
)
This can also be written with an IN statement, but EXIST is much more efficient
To remove overlapping dates you can use:
Demo
CREATE TABLE #TABLEA( TrainerID INT, StartDate DATETIME, EndDate DATETIME);
INSERT INTO #TABLEA
SELECT 1234, '10-1-2015 08:30', '10-1-2015 09:00'
UNION ALL SELECT 1234 , '10-1-2015 08:45', '10-1-2015 09:15'
UNION ALL SELECT 1234 , '10-1-2015 09:30', '10-1-2015 10:00'
UNION ALL SELECT 2345 , '10-1-2015 08:45', '10-1-2015 09:15'
UNION ALL SELECT 2345 , '10-1-2015 09:30', '10-1-2015 10:00';
SELECT
D.TrainerID,
[StartTime] = D.StartDate,
[EndTime] = (SELECT MIN(E.EndDate)
FROM #TABLEA E
WHERE E.EndDate >= D.EndDate
AND E.TrainerID = D.TrainerID
AND NOT EXISTS (SELECT 1
FROM #TABLEA E2
WHERE E.StartDate < E2.StartDate
AND E.EndDate > E2.StartDate
AND E.TrainerID = E2.TrainerID))
FROM #TABLEA D
WHERE NOT EXISTS ( SELECT 1
FROM #TABLEA D2
WHERE D.StartDate < D2.EndDate
AND D.EndDate > D2.EndDate
AND D.TrainerID = D2.TrainerID);
You can use below code to get the required row, however based on your logic row from next trainer id (i.e. 2345) will also be qualified
DECLARE #Trainers TABLE
(
TrainerId INT,
Start_Time datetime,
End_Time datetime
)
INSERT INTO #Trainers VALUES
(1234,'10-1-2015 08:30','10-1-2015 09:00 '),
(1234,'10-1-2015 08:45','10-1-2015 09:15'),
(1234,'10-1-2015 09:30','10-1-2015 10:00'),
(2345 ,' 10-1-2015 08:45','10-1-2015 09:15'),
(2345 ,' 10-1-2015 09:30 ',' 10-1-2015 10:00')
;WITH TrainersTemp AS
(
SELECT *, ROW_NUMBER() OVER ( ORDER BY trainerid) AS rn
FROM #Trainers
)
SELECT CX.TrainerId, CX.Start_Time, CX.End_Time
FROM TrainersTemp CX JOIN TrainersTemp CY
ON CX.rn = CY.rn + 1
WHERE CY.End_Time < CX.Start_Time
Demo (SQL fiddle is down again)
or if you want to see all rows except the faulty one then use below code
;WITH TrainersTempAll AS
(
SELECT *, ROW_NUMBER() OVER ( ORDER BY trainerid) AS rn
FROM #Trainers
)
SELECT CX.TrainerId, CX.Start_Time, CX.End_Time
FROM TrainersTempAll CX JOIN TrainersTempAll CY
ON CX.rn = CY.rn + 1
Firstly you should sort by trainerId and Start_time. And then join two tables with correct condition.
Try this query:
;WITH TrainersTemp AS
(
SELECT *, ROW_NUMBER() OVER ( ORDER BY trainerid, Start_Time) AS row_num
FROM Trainers
)
select t2.* from TrainersTemp t1
join TrainersTemp t2 on t1.TrainerId = t2.TrainerId and t1.row_num = t2.row_num-1
where t2.Start_Time<t1.End_Time
As you use SQL Server 2012 you can use LAG function, which would be likely more efficient than self-join. The query becomes pretty simple as well.
For each row LAG gives you EndTime from the previous row (partitioned by TrainerID). Then just compare StartTime from the current row with EndTime from the previous row.
SQL Fiddle
WITH
CTE
AS
(
SELECT
TrainerID
,StartTime
,EndTime
,LAG(EndTime) OVER(PARTITION BY TrainerID ORDER BY StartTime) AS PrevEndTime
FROM TableA
)
SELECT
TrainerID
,StartTime
,EndTime
FROM CTE
WHERE StartTime < PrevEndTime
;
Results:
| TrainerID | StartTime | EndTime |
|-----------|---------------------------|---------------------------|
| 1234 | October, 01 2015 08:45:00 | October, 01 2015 09:15:00 |

Displaying weeks as columns

Below is the script to display the number of weeks between the given dates.
SET DATEFIRST 1
SELECT ta.account, ta.customer, SUM(amount), DATEPART(ww,ta.dt) WeekNumber
FROM tablename ta
WHERE dt >= '12/01/2011 00:00:00'
and dt < '12/29/2011 00:00:00'
GROUP BY ta.account, ta.customer, DATEPART(ww,ta.dt)
How do I display the diff weeks as diff columns in my result. Any suggestion would be helpful.
Sample O/P for the above is:
Date Account Customer TotalSeconds Amount WeekNumber
2011-11-01 xx0918252 198303792R 394 2.99 45
2011-11-08 xx1006979 200100567G 92 0.16 46
2011-11-15 xx1005385 A6863744I 492 1.275 47
2011-11-21 xx1012872 D7874694G 770 0.52 48
2011-11-28 xx1006419 C7112151H 1904 2.64 49
2011-11-28 xx1006420 G7378945A 77 0.3 49
I want the O/P like:
Date Account Customer TotalSeconds Amount WeekNumber45 WeekNumber46 WeekNumber47 WeekNumber8 WeekNumber49
and their corresponding data. Hope u understand my question. Thanks in advance.
Hi All, Thanks for the suggestions n help. Finally, I got the results that i wanted for time being. I still believe that it is hard coding. Is there a better solution for this. Thanks in advance. My code is as follows:
SELECT ta.account, ta.customer,
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '49' THEN amount END),0) AS "Week49",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '50' THEN amount END),0) AS "Week50",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '51' THEN amount END),0) AS "Week51",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '52' THEN amount END),0) AS "Week52",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '53' THEN amount END),0) AS "Week53",
FROM (
select * from tablename
where dt >= '12/01/2011 00:00:00' and dt <= '12/31/2011 00:00:00'
) ta
group by ta.account, ta.customer
First of all I would put your result in temporary table for later calculations. Let's imagine that following CTE is your result:
if object_id('tempdb..#tab') is not null drop table #tab
;with cte (Date,Account,Customer,TotalSeconds,Amount,WeekNumber) as (
select cast('20111101' as datetime),'xx0918252','198303792R',394,2.99,45 union all
select '20111108','xx1006979','200100567G',92,0.16,46 union all
select '20111115','xx1005385','A6863744I',492,1.275,47 union all
select '20111121','xx1012872','D7874694G',770,0.52,48 union all
select '20111128','xx1006419','C7112151H',1904,2.64,49 union all
select '20111128','xx1006420','G7378945A',77,0.3,49
)
select * into #tab from cte
Now your computed data is in #tab table and the following query returns pivoted table for those weeknumbers:
select date, account, customer, totalSeconds, amount, [45], [46], [47], [48], [49] from
(
select date, account, customer, totalSeconds, amount, weeknumber as weeknumber from #tab
) src
pivot
(
max(weeknumber) for weekNumber in ([45], [46], [47], [48], [49])
) pvt
Dynamic version of this query might look like this:
declare #sql nvarchar(max), #cols varchar(max)
select #cols = coalesce(#cols + ',', '') + '[' + cast(weeknumber as varchar) + ']'
from (select distinct weeknumber from #tab) t
order by weeknumber
set #sql = N'
select date, account, customer, totalSeconds, amount, ' + #cols + ' from
(
select date, account, customer, totalSeconds, amount, weeknumber as weeknumber from #tab
) src
pivot
(
max(weeknumber) for weekNumber in (' + #cols + ')
) pvt
'
exec sp_executesql #sql
The result (in both cases):
date account customer totalSeconds amount 45 46 47 48 49
----------------------- --------- ---------- ------------ ---------- ------ ------ ------ ------ ------
2011-11-01 00:00:00.000 xx0918252 198303792R 394 2.990 45 NULL NULL NULL NULL
2011-11-08 00:00:00.000 xx1006979 200100567G 92 0.160 NULL 46 NULL NULL NULL
2011-11-15 00:00:00.000 xx1005385 A6863744I 492 1.275 NULL NULL 47 NULL NULL
2011-11-21 00:00:00.000 xx1012872 D7874694G 770 0.520 NULL NULL NULL 48 NULL
2011-11-28 00:00:00.000 xx1006419 C7112151H 1904 2.640 NULL NULL NULL NULL 49
2011-11-28 00:00:00.000 xx1006420 G7378945A 77 0.300 NULL NULL NULL NULL 49
Take a look at the PIVOT function.
Tsql pivot command
T-SQL Pivot function combined with dynamic SQL. Examples:
SQL Server 2005 Pivot on Unknown Number of Columns.
Pivots with Dynamic Columns in SQL Server 2005/2008.