SQL cross tab pivot query - sql

I have a table as below.
CaseID StatusID StageID CaseRegisterTime City
1 1 5 datetime XYZ
2 1 5 datetime ABC
Now I want its Citywise count and only for only specific dates, and also in condition for statusid = 1 and stageid = 5.
Cities CurrentDate-1 CurrentDate-2 January2012-CurrentDate-3
XYZ 5 51 5008
JUS 0 0 125
ABC 1 0 48
I want my header to group cases for CaseRegisterTime as shown above.
Please help.

Use case when to convert your dates of interest to 'CurrentDate-1' and 'CurrentDate-2', and then pivot the results, using this strings as the new columns.
Alternatively, you can do something like this:
select City, sum(Date1) as Date1, sum(Date2) as Date2
from(
select City,
case when CaseRegisterTime='2012-01-01' then 1 else 0 end as Date1,
case when CaseRegisterTime='2012-15-01' then 1 else 0 end as Date2
from sample
) as T
group by City
you'd also have to filter out the registers which doesn't have the desired date.

Here's one of many ways to do it in SQL Server 2008 (using the Date datatype):
select distinct a.City as Cities
, (select count(*)
from MyTable
where CaseRegisterTime >= cast(getdate() - 1 as date)
and CaseRegisterTime < cast(getdate() - 0 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [CurrentDate-1]
, (select count(*)
from MyTable
where CaseRegisterTime >= cast(getdate() - 2 as date)
and CaseRegisterTime < cast(getdate() - 1 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [CurrentDate-2]
, (select count(*)
from MyTable
where CaseRegisterTime >= cast('20120101' as date)
and CaseRegisterTime < cast(getdate() - 2 as date)
and StatusID = a.StatusID
and StageID = a.StageID
and City = a.City
) as [January2012-CurrentDate-3]
from MyTable a
where a.StatusID = 1
and a.StageID = 5
Update
The case and sum method #JotaBe uses is about twice as fast on my box (with many less scans and reads), so here's what that could look like:
select a.City as Cities
, sum(a.[CurrentDate-1]) as [CurrentDate-1]
, sum(a.[CurrentDate-2]) as [CurrentDate-2]
, sum(a.[January2012-CurrentDate-3]) as [January2012-CurrentDate-3]
from (
select City
, case when CaseRegisterTime >= cast(getdate() - 1 as date)
and CaseRegisterTime < cast(getdate() - 0 as date)
then 1 else 0 end [CurrentDate-1]
, case when CaseRegisterTime >= cast(getdate() - 2 as date)
and CaseRegisterTime < cast(getdate() - 1 as date)
then 1 else 0 end [CurrentDate-2]
, case when CaseRegisterTime >= cast('20120101' as date)
and CaseRegisterTime < cast(getdate() - 2 as date)
then 1 else 0 end [January2012-CurrentDate-3]
from MyTable
where StatusID = 1
and StageID = 5
) as a
group by a.City

Something like this will do:
begin tran;
go
create table #t1(
ID int identity,
City varchar,
RegisterDate datetime
);
declare #firstDate datetime, #secondDate datetime;
set #firstDate = '2012-1-1';
set #secondDate = '2012-1-2';
insert into #t1 values
('A', #firstDate),
('A', #firstDate),
('B', #firstDate),
('B', #firstDate),
('B', #firstDate),
('A', #secondDate),
('A', #secondDate),
('A', #secondDate),
('B', #secondDate),
('B', #secondDate);
select * from #t1;
select pvt.*
from(
select ID, City, RegisterDate
from #t1
) a
pivot(
count(a.ID)
for a.RegisterDate in ([2012-1-1], [2012-1-2])
) as pvt;
drop table #t1;
go
rollback tran;

Related

Iterate value dynamically

I'm using the below query to calculate a budget value dynamically means iterating upto selected date value.
SUM(case when Name = 'Budget' then Value + ((Value/#TotaldaysinMonth) *
#DaysPastinMonth) end) as [Budget]
Here variable #DaysPastinMonth should be dynamic. Means if I select a date as 03/31/2017. Then the query should run upto the previous month value. Another example is if I select August, then I need to run query from Jan-Aug.
For Jan
SUM(case when Name = 'Budget' then Value + ((Value/#TotaldaysinMonth) *
#DaysPastinJanMonth) end) as [Budget]
For Feb
SUM(case when Name = 'Budget' then Value + ((Value/#TotaldaysinMonth) *
#DaysPastinFebMonth) end) as [Budget]
For Mar
SUM(case when Name = 'Budget' then Value + ((Value/#TotaldaysinMonth) *
#DaysPastinMarMonth) end) as [Budget]
Also I have created variables for all the 12 months which holds DaysPastinMonth.
Can anyone suggest how this can be achieved using case statement.
You are thinking about this in loop when you could do it with set based operations.
----------------------------------------------------------
--Create a table of dates for testing
----------------------------------------------------------
if object_id('tempdb..#dates') is not null
drop table #dates
create table #dates(d date
,RN bigint)
declare #sdate datetime='2017-01-01 00:00'
declare #edate datetime='2017-7-31 00:00'
insert into #dates
select
DATEADD(d,number,#sdate)
,row_number() over (order by (select null)) as RN
from
master..spt_values
where
type='P'
and number<=datediff(d,#sdate,#edate)
declare #numOfDays int = (select count(*) from #dates)
----------------------------------------------------------
--Populate Test Data
----------------------------------------------------------
if object_id('tempdb..#testTable') is not null
drop table #testTable
create table #testTable([Name] varchar(64),
[Value] decimal (16,4),
DT datetime)
insert into #testTable ([Name],[Value],DT)
select
'Budget'
,r.randomNumber
,d.d
from
#dates d
inner join
(SELECT TOP (select #numOfDays)
randomNumber,
row_number() over (order by (select null)) as RN
FROM (
SELECT CAST(ABS(CAST(NEWID() AS binary(6)) %100000) + RAND() AS DECIMAL (16,4)) + 1 randomNumber
FROM sysobjects) sample
GROUP BY randomNumber
ORDER BY randomNumber DESC) r on r.RN = d.RN
union all
select
'Not The Budget'
,r.randomNumber
,d.d
from
#dates d
inner join
(SELECT TOP (select #numOfDays)
randomNumber,
row_number() over (order by (select null)) as RN
FROM (
SELECT CAST(ABS(CAST(NEWID() AS binary(6)) %100000) + RAND() AS DECIMAL (16,4)) + 1 randomNumber
FROM sysobjects) sample
GROUP BY randomNumber
ORDER BY randomNumber DESC) r on r.RN = d.RN
----------------------------------------------------------
--Instead of making your variables "dynamic" which
--would likely consist of some loop, just pass in the
--month you care about and let SQL do the work
----------------------------------------------------------
declare #month datetime = '2016-03-31'
select
DT
,[Value]
,[Name]
,sum(case when [Name] = 'Budget'
then [Value] +
(([Value] / (DATEDIFF(day,DATEADD(month, DATEDIFF(month, 0, #month), 0),#month)))
*
(DATEDIFF(DAY,DATEADD(MONTH, DATEDIFF(MONTH, 0, #month)-1, 0),DATEADD(MONTH, DATEDIFF(MONTH, -1, #month)-1, -1)))) end) as Budget
from
#testTable
where
DT >= DATEADD(yy, DATEDIFF(yy, 0, #month), 0) --this is Jan 1 of the year associated with your vairable
group by
DT
,[Name]
,[Value]

How to show monthly data even if there are no results yet SQL Server 2008

So I wrote a script that would show monthly premium. Say if you want to view the total premium up to November, you can pass through a parameter in in SSRS to pick 1/1/2016 - 11/30/2016. This would only show the data up until november, hoever, I would like to show it up until december even if there are no records there. How do I go about doing this in SQL? Here is my script so far:
SELECT lc.[Date]
,lc.Carrier
,lc.[Direct Ceded Written Premium]
,cast(cast(year(lc.[date]) as varchar(4)) + '-' + cast(month(lc.[date]) as varchar(2)) + '-01' as date) as [begofmonth]
from
(
SELECT
CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN cast(pd.TransactionDate as DATE)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN cast(pd.EffectiveDate as DATE)
ELSE cast(pd.TransactionEffDate as date)
END AS [Date]
,CASE WHEN LEFT(PD.POLICYNUM, 3) = 'ORV'
THEN 'Palomar Value Select OR'
WHEN LEFT(PD.POLICYNUM, 3) = 'VSE'
THEN 'Palomar Value Select CA'
WHEN LEFT(PD.POLICYNUM, 3) = 'WAV'
THEN 'Palomar Value Select WA'
ELSE 'Palomar' END AS [Carrier]
,ISNULL(SUM(pd.WrittenPremium), 0) AS [Direct Ceded Written Premium]
FROM premdetail pd
JOIN transactionpremium tp ON pd.systemid = tp.systemid
AND pd.transactionpremiumid = tp.id
JOIN transactionhistory th ON tp.systemid = th.systemid
AND tp.cmmcontainer = th.cmmcontainer
AND tp.parentid = th.id
JOIN basicpolicy bp ON th.systemid = bp.systemid
AND th.cmmcontainer = bp.cmmcontainer
AND th.parentid = bp.id
WHERE
(CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN pd.TransactionDate
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN pd.EffectiveDate
ELSE pd.TransactionEffDate
END) > = CAST(#StartDate AS DATE)
AND (CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN pd.TransactionDate
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN pd.EffectiveDate
ELSE pd.TransactionEffDate
END) < CAST(#EndDate + 1 AS DATE)
AND (bp.carriercd = #ResEQCarrierCd
OR #ResEQCarrierCd = 'All')
GROUP BY
CASE
WHEN pd.TransactionEffDate < pd.TransactionDate THEN cast(pd.TransactionDate as DATE)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN cast(pd.EffectiveDate as DATE)
ELSE cast(pd.TransactionEffDate as date)
END
,CONVERT(VARCHAR, pd.EffectiveDate, 101)
,CONVERT(VARCHAR, pd.ExpirationDate, 101)
,CASE
WHEN LEFT(PD.POLICYNUM, 3) = 'ORV'
THEN 'Palomar Value Select OR'
WHEN LEFT(PD.POLICYNUM, 3) = 'VSE'
THEN 'Palomar Value Select CA'
WHEN LEFT(PD.POLICYNUM, 3) = 'WAV'
THEN 'Palomar Value Select WA'
ELSE 'Palomar'
END
,CASE
WHEN pd.TransactionCode = 'EN' THEN CONVERT(VARCHAR, th.TransactionEffectiveDt, 101)
ELSE ''
END
,CONVERT(VARCHAR, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(m, 0, th.transactiondt) + 1, 0)), 101)
,CASE
WHEN pd.TransactionEffDate < CAST(CONVERT(VARCHAR, pd.TransactionDate, 101) AS SMALLDATETIME) THEN CONVERT(VARCHAR, pd.TransactionDate, 101)
WHEN pd.TransactionEffDate < pd.EffectiveDate THEN CONVERT(VARCHAR, pd.EffectiveDate, 101)
ELSE CONVERT(VARCHAR, pd.TransactionEffDate, 101)
END
) lc
ORDER BY lc.[Date], lc.[Carrier], lc.[Direct Ceded Written Premium]
With the parameter that I have, it would only show up until November. However, I would like it to show the whole year, up to December at in this case, even if there are no data there since I didn't pick the enddate variable to be december. I attached an example screenshot of what it should look like when exported to excel.
Just to give you an idea:
declare #tbl TABLE(ID INT IDENTITY,SomeValue VARCHAR(100),SomeDate DATE);
INSERT INTO #tbl VALUES('Some date in March',{d'2016-03-05'}),('Some date in June',{d'2016-06-30'});
WITH AllMonths AS
(
SELECT 1 AS MonthIndex
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
UNION ALL SELECT 10
UNION ALL SELECT 11
UNION ALL SELECT 12
)
SELECT MonthIndex
,t.*
FROM AllMonths
LEFT JOIN #tbl AS t ON MONTH(t.SomeDate)=MonthIndex
The result
1 NULL NULL NULL
2 NULL NULL NULL
3 1 Some date in March 2016-03-05
4 NULL NULL NULL
5 NULL NULL NULL
6 2 Some date in June 2016-06-30
7 NULL NULL NULL
8 NULL NULL NULL
9 NULL NULL NULL
10 NULL NULL NULL
11 NULL NULL NULL
12 NULL NULL NULL
There are many ways to create a tally table
CTE with ROW_NUMBER()
A list like in my example
A physical table
It is a good idea to maintain a numbers/DATE table!
In a previous answer I showed one way to create such a table.

How do i take the 12th value in a SQL select statement?

I have a very large SQL database that I am pulling data to a web page. Instead of pulling every value, I want to take every 12th value. Is there a way to modify my current select statement?
SELECT *
FROM (
SELECT CAST(DateTimeUTC as SmallDateTime) as [DateTime],
CASE When DataValue = '-9999' Then null
When DataValue < '-60' Then null
Else DataValue
End DataValue, VariableID
FROM DataValues
WHERE SiteID = #siteID and VariableID IN(9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)
) TableDate
PIVOT (SUM(DataValue) FOR VariableID IN ([9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30])) PivotTable ORDER BY [DateTime]
END
This works except the data is staggered from one column to the next. I am not sure why all the data points don't start at the same location.
See the screen shot below.
=
Using this theory (SQL Server) -
with rNum As(
SELECT t.*,RowNum = row_number() over (order by date)
FROM testdb.dbo.testtable t
)
select * from rNum where (RowNum % 12) = 0
Something like this -
with dVal As(
Select RowNum = row_number() over (order by datetime),DataValues.*
from datavalues)
SELECT *
FROM (
SELECT CAST(DateTimeUTC as SmallDateTime) as [DateTime],
CASE When DataValue = '-9999' Then null
When DataValue < '-60' Then null
Else DataValue
End DataValue, VariableID
FROM dVal
WHERE
/* divide by 12 has no remainder */
(RowNum % 12) = 0 and
SiteID = #siteID and VariableID IN(9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)
) TableDate
PIVOT (SUM(DataValue) FOR VariableID IN ([9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30])) PivotTable ORDER BY [DateTime]
or,
Select * from DataValues d
where (Select count(*) from datavalues
where DateTimeUTC < d.DateTimeUTC) % 12 = 0
to start at the 12th row, instead of the first row,
Select * from DataValues d
where (Select count(*) from datavalues
where DateTimeUTC <= d.DateTimeUTC) % 12 = 0
or
Select * from DataValues d
where (Select count(*) from datavalues
where DateTimeUTC < d.DateTimeUTC) % 12 = 11

trouble in query

hey every one i have this record
id date hours groupkey
1 1-12-2016 1 NULL
2 2-12-2016 2 NULL
3 3-12-2016 1 3
4 4-12-2016 1 3
5 5-12-2016 1 3
and i want this
id startdate enddate hours
1 1-12-2016 1-12-2016 1
2 2-12-2016 2-12-2016 2
3 3-12-2016 5-12-2016 3
i am using this query
SELECT Max(Isnull(groupkey, id)) AS id,
Min(date) AS startdate,
Max(date) AS enddate,
Sum(timeoffhours) AS hours,
CASE
WHEN Min(groupkey) IS NULL THEN 'No'
ELSE 'Yes'
END Status
FROM table
WHERE employeekey = 20
AND date >= '1/1/2016'
AND date <= '12/31/2016'
GROUP BY groupkey
but it is making one row for null group key please help me
You should GROUP BY Isnull(groupkey, id)) to solve your issue here. You're still grouping on the regular groupkey.
Try in dynamic table
SELECT
id, startdate, enddate, hours,
CASE WHEN mingroup IS NULL THEN 'No' ELSE 'YES' END AS status
FROM
(SELECT
MAX(ISNULL(groupkey, id)) AS id,
MIN(date) AS startdate,
MAX(date) AS enddate,
SUM(timeoffhours) AS hours,
MIN(groupkey) AS mingroup
FROM
table
WHERE
employeekey = 20
AND date >= '1/1/2016'
AND date <= '12/31/2016'
GROUP BY
groupkey)
BEGIN TRAN
CREATE TABLE #Temp (id INT IDENTITY(1,1) , _date DATE ,_hours INT , groupkey INT)
CREATE TABLE #OutPutTemp (_id INT , _Startdate DATE ,_EndDate DATE, _Hours INT)
INSERT INTO #Temp (_date ,_hours , groupkey )
SELECT '1-12-2016' ,1,NULL UNION ALL
SELECT '2-12-2016' ,2,NULL UNION ALL
SELECT '3-12-2016' ,1,3 UNION ALL
SELECT '4-12-2016' ,1,3 UNION ALL
SELECT '5-12-2016' ,1,3
INSERT INTO #OutPutTemp(_id , _Startdate ,_EndDate,_Hours)
SELECT id , _date , _date , _hours
FROM #Temp
WHERE ISNULL(groupkey,0) = 0
INSERT INTO #OutPutTemp(_id)
SELECT groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
UPDATE #OutPutTemp SET _Startdate = Startdate
FROM
(
SELECT MIN(_date) Startdate ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)A
WHERE _id = groupkey
UPDATE #OutPutTemp SET _EndDate = EndDate
FROM
(
SELECT MAX(_date) EndDate ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)B
WHERE _id = groupkey
UPDATE #OutPutTemp SET _hours = tothours
FROM
(
SELECT SUM(_hours) tothours ,groupkey
FROM #Temp
WHERE ISNULL(groupkey,0) <> 0
GROUP BY groupkey
)C
WHERE _id = groupkey
SELECT * FROM #OutPutTemp
ROLLBACK TRAN

SQL - possible pivot issue

I have a table with the following structure
Item Id, Start Date, End Date
1 , 2015-01-01, 2015-06-01
2 , 2015-01-01, 2015-02-01
3 , 2015-03-01, 2015-08-01
4 , 2015-06-01, 2015-10-01
I would like to view results so i will have each month in the column.
Each row will contain the id of the item that is within this month.
Example:
I am asking for all items that are within 2015-01-01 to 2015-03-01.
The results should display, in columns, all the months within that range. So in this case it's 3 columns, Jan Feb and March.
The number of rows will be the total number of items that are within that range BUT each cell should show value of item id only if that item is within range:
example:
2015-01-01, 2015-02-01, 2015-03-01
1 1 1
2 2 NULL
NULL NULL 3
In order to use pivot, you can create a recursive cte get each item id and the list of months it covers, then pivot the cte.
;WITH cte AS
(
SELECT [Item Id], [Start Date], [End Date]
FROM Table1
WHERE [Start Date] BETWEEN '2015-01-01' AND '2015-03-01' --Date Range you want
OR [End Date] BETWEEN '2015-01-01' AND '2015-03-01' --Date Range you want
UNION ALL
SELECT [Item Id], DATEADD(MONTH, 1, [Start Date]), [End Date]
FROM cte
WHERE DATEADD(MONTH, 1, [Start Date]) <= [End Date]
)
SELECT [2015-01-01],[2015-02-01],[2015-03-01] --List of Dates you want
FROM (
SELECT [Item Id] rn, -- need a unique id here to give one row per record
[Item Id],
CONVERT(VARCHAR(10), [Start Date], 120) [Start Date] -- Format date to yyyy-mm-dd
FROM cte
) t
PIVOT
( MAX([Item Id])
FOR [Start Date] IN ([2015-01-01],[2015-02-01],[2015-03-01])
) p
You most likely need to use dynamic SQL.
This is your data:
declare #first date = '20150101';
declare #last date = '20150301';
Create Table #items(ItemId int, StartDate date, EndDate date);
Insert into #items(ItemId, StartDate, EndDate) values
(1, '2015-01-01', '2015-06-01')
, (2, '2015-01-01', '2015-02-01')
, (3, '2015-03-01', '2015-08-01')
, (4, '2015-06-01', '2015-10-01');
You first need to get the range of values and columns:
declare #values varchar(max);
declare #cols varchar(max);
with range(d) as (
Select top(DATEDIFF(month, #first, #last)+1) cast(DATEADD(month, ROW_NUMBER() over(order by (select 0))-1, #first) as varchar(20))
From (
Select 1 From (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as x1(n)
Cross Join (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as x2(n)
) as x(n)
)
Select #values = coalesce(''+#values+ ', ', ' ') + '('''+d+''')'
, #cols = coalesce(''+#cols+ ', ', ' ') + '['+left(DATENAME(month, d), 3)+CAST(year(d) as char(4))+']'
From range
;
This basically create a row for each date between #first and #last and concatenate them with parenthesis and commas (#values) or brackets (#cols).
Content in #values and #cols look like this:
#values = ('2015-01-01'), ('2015-02-01'), ('2015-03-01')
#cols = [Jan2015], [Feb2015], [Mar2015]
You then create a SQL script using theses 2 variables:
declare #sql nvarchar(max);
Set #sql = '
Select *
From (
Select i.ItemId, d = left(DATENAME(month, r.d), 3)+CAST(year(r.d) as char(4))
, id = case when r.d >= i.StartDate and r.d <= i.EndDate then i.ItemId end
From (values'+#values+') as r(d)
Cross Join (Select ItemId, StartDate, EndDate From #items
Where (#first >= StartDate and #first <= EndDate) or (#last >= StartDate and #last <= EndDate)
) i
) as dates
Pivot (
min(id)
For d in('+#cols+')
) as piv
';
This is the pivot query.
Created SQL will look like this in this example:
Select *
From (
Select i.ItemId, d = left(DATENAME(month, r.d), 3)+CAST(year(r.d) as char(4))
, id = case when r.d >= i.StartDate and r.d <= i.EndDate then i.ItemId end
From (values ('2015-01-01'), ('2015-02-01'), ('2015-03-01')) as r(d)
Cross Join (Select ItemId, StartDate, EndDate From #items
Where (#first >= StartDate and #first <= EndDate) or (#last >= StartDate and #last <= EndDate)
) i
) as dates
Pivot (
min(id)
For d in( [Jan2015], [Feb2015], [Mar2015])
) as piv
You can finally execute the script:
exec sp_executesql #sql, N'#first date, #last date', #first, #last;
Ouput:
ItemId Jan2015 Feb2015 Mar2015
1 1 1 1
2 2 2 NULL
3 NULL NULL 3
Probably something like....
Select
CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 1 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-01-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 2 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-02-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 3 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-03-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 4 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-04-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 5 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-05-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 6 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-06-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 7 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-07-01]
,CASE WHEN EXISTS (SELECT 1 FROM TableName where Month(Start) = 8 AND ItemId = t.ItemId) THEN t.ItemId END AS [2015-08-01]
,..... and so on..... for all the other months...
from TableName t