2015-11-03 2 views
0

У меня есть таблица со следующей структуройSQL - возможно проблема поворота

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 

Я хотел бы, чтобы просмотреть результаты так что я буду иметь каждый месяц в колонке.

В каждой строке будет содержаться идентификатор объекта, который находится в этом месяце.

Пример: Я прошу все предметы, которые находятся в пределах 2015-01-01, до 2015-03-01.

Результаты должны отображаться в столбцах все месяцы в пределах этого диапазона. Таким образом, в этом случае это 3 столбца, JanFeb и March.

Количество строк будет общее количество элементов, которые находятся в пределах этого диапазона, но каждая ячейка должна показать значение определенного товара, только если этот элемент находится в пределах диапазона:

пример:

2015-01-01, 2015-02-01, 2015-03-01 
    1   1   1 
    2   2   NULL 
    NULL  NULL  3 

ответ

1

для того, чтобы использовать стержень, вы можете создать рекурсивный КТР получить каждый пункт идентификатор и список месяцев покрывает, затем откинуть КТР.

;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 
+0

Awesome, спасибо! –

0

Возможно, что-то вроде ....

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 
1

Вам, скорее всего, придется использовать динамический SQL.

Это ваши данные:

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'); 

Вы в первую очередь необходимо, чтобы получить диапазон значений и столбцов:

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(''[email protected]+ ', ', ' ') + '('''+d+''')' 
    , @cols = coalesce(''[email protected]+ ', ', ' ') + '['+left(DATENAME(month, d), 3)+CAST(year(d) as char(4))+']' 
From range 
; 

В основном это создать строку для каждого date между @first и @last и соединить их скобками и запятыми (@values) или скобками (@cols).

Содержание в @values ​​и @cols выглядеть следующим образом:

@values = ('2015-01-01'), ('2015-02-01'), ('2015-03-01') 
@cols = [Jan2015], [Feb2015], [Mar2015] 

Вы затем создать SQL скрипт, используя эти 2 переменные:

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'[email protected]+') 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('[email protected]+') 
) as piv 
'; 

Это сводный запрос.

Созданный 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 ('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 

Вы можете, наконец, выполнить скрипт:

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 
Смежные вопросы