2016-12-07 3 views
1

У меня есть таблица с данными, как этотОбъединение нескольких строк в TSQL запроса

Road Item Response added_on 
1  82 Yes  7/11/16 
1  83 Yes  7/11/16 
1  84 Yes  7/11/16 
2  82 Yes  8/11/16 
2  83 No  8/11/16 
2  85 Yes  8/11/16 

Это отражает оценку дороги, где все время оценивается «вещь». Некоторые предметы всегда будут выполняться во время оценки (82, 83), где другие необязательны (84, 85). Я хочу вернуть что-то, что объединяет все результаты оценки для дороги/даты, возвращая значение null, если этот предмет не был оценен. А также возвращение результатов только в прошлом месяце. Например,

Road 82 83 84 85 added_on 
1  Yes Yes Yes  7/11/16 
2  Yes No  Yes 8/11/16 

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

FROM assess AS A 
JOIN assess AS B 
ON A.road = B.road AND a.added_on = B.added on 
JOIN assess AS C 
ON A.road = C.road AND a.added_on = C.added on 
JOIN assess AS D 
ON A.road = D.road AND a.added_on = D.added on 

WHERE A.item = '81' 
AND B.item = '82' 
AND (C.item = '83' OR C.item IS NULL) 
AND (D.item = '84' OR D.item IS NULL) 
AND datepart(month,A.added_on) = datepart(month,getdate()) -1 

Чтобы уточнить,

-не дороги оценивается более чем один раз в день
-Каждый элемент только оценивается один раз, а иногда NULL т.е. не применяется
-Несколько дороги оцениваются каждый день
-Этот таблица имеет другие оценки, но мы не беспокоимся об этом.

Любые идеи? Использование SQL Server 2008. Спасибо.

+0

Сколько предметов существует, и является ли это число фиксированным и известным? –

+0

Похоже, вы ищете что-то вроде PIVOT - см. Https://msdn.microsoft.com/en-us/library/ms177410.aspx. –

ответ

1

Предполагая, что вы должны пойти Dynamic

Declare @SQL varchar(max) 
Select @SQL = Stuff((Select Distinct ',' + QuoteName(Item) From YourTable Order By 1 For XML Path('')),1,1,'') 
Select @SQL = 'Select [Road],' + @SQL + ',[added_on] 
       From YourTable 
       Pivot (max(Response) For Item in (' + @SQL + ')) p' 
Exec(@SQL); 

Возвращает

enter image description here

EDIT - The SQL Вырабатываемые следующим образом. (Только в случае, если вы не можете пойти динамические)

Select [Road],[82],[83],[84],[85],[added_on] 
From YourTable 
Pivot (max(Response) For Item in ([82],[83],[84],[85])) p 
+0

'PIVOT' - это, вероятно, способ пойти в этом случае. – Aquillo

0

Другим способ достижения этой цели менее изящен, но использует основные операции, если вы не хотите использовать pivot.

нагрузки до тестовых данных

create table #assess (road int, item varchar(10), response varchar(3), added_on date) 
insert #assess(road, item, response, added_on) 
values 
    (1, '82', 'Yes', '2016-07-11') 
, (1, '83', 'Yes', '2016-07-11') 
, (1, '84', 'Yes', '2016-07-11') 
, (2, '82', 'Yes', '2016-08-11') 
, (2, '83', 'No', '2016-08-11') 
, (2, '85', 'Yes', '2016-08-11') 

обрабатывать данные

-- Get every possible `item` 
select distinct item into #items from #assess 

-- Ensure every road/added_on combination has all possible values of `item` 
-- If the combination does not exist in original data, leave `response` as blank 
select road, added_on, i.item, cast('' as varchar(3)) as response into #assess2 
from #items as i cross join #assess AS A 
group by road, added_on, i.item 

update a set response = b.response 
from #assess2 a inner join #assess b on A.road = B.road AND a.added_on = B.added_on AND a.item = b.item 

-- Join table to itself 4 times - inner join if `item` must exist or left join if `item` is optional 
select a.road, a.added_on, a.response as '82', b.response as '83', c.response as '84', d.response as '85' 
FROM #assess2 AS A 
INNER JOIN #assess2 AS B ON A.road = B.road AND a.added_on = B.added_on 
LEFT JOIN #assess2 AS C  ON A.road = C.road AND a.added_on = C.added_on 
LEFT JOIN #assess2 AS D  ON A.road = D.road AND a.added_on = D.added_on 

WHERE A.item = '82' 
AND B.item = '83' 
AND (C.item = '84' OR C.item IS NULL) 
AND (D.item = '85' OR D.item IS NULL) 
--AND datepart(month,A.added_on) = datepart(month,getdate()) -1 

результирующий набор является:

road added_on 82 83 84 85 
1  2016-07-11 Yes Yes Yes 
2  2016-08-11 Yes No  Yes 
0

Я хотел бы сделать это с помощью условной агрегации:

select road, 
     max(case when item = 82 then response end) as response_82, 
     max(case when item = 83 then response end) as response_83, 
     max(case when item = 84 then response end) as response_84, 
     max(case when item = 85 then response end) as response_85, 
     added_on 
from t 
group by road, added_on 
order by road; 

Для компонента месяца вы можете добавить пункт where.Один метод:

where year(date_added) * 12 + month(date_added) = year(getdate())*12 + month(getdate()) - 1 

Или, вы можете использовать логику, как это:

where date_added < dateadd(day, 1 - day(getdate()), cast(getdate() as date)) and 
     date_added >= dateadd(month, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date))) 

Второй выглядит более сложным, но это sargable, что означает, что индекс date_added можно использовать (если один доступен).