我有一个包含这样数据的表
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 :(得分: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);
返回
编辑 - SQL Generated如下。 (以防万一你不能去 动态)
Select [Road],[82],[83],[84],[85],[added_on]
From YourTable
Pivot (max(Response) For Item in ([82],[83],[84],[85]) ) p
答案 1 :(得分: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
答案 2 :(得分: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
上的索引(如果有的话)。