2016-12-07 103 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 

爲了澄清,

-no道路被評估超過每天一次
- 每個項目僅評估一次,有時爲NULL,即不適用更
-multiple道路每天評估
- 這個表格有其他評估,但我們並不擔心這些。

任何想法?使用SQL Server 2008.謝謝。

+0

有多少物品,並且這個數字是固定的和已知的? –

+0

聽起來像你正在尋找類似PIVOT的東西 - 請參閱https://msdn.microsoft.com/en-us/library/ms177410.aspx。 –

回答

1

假設你需要去動態

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

編輯 - 生成的是如下的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))) 

第二個看起來比較複雜,但它是優化搜索,這意味着在date_added索引都可以使用(如果一個是可用的)。