【问题标题】:Combining multiple rows in TSQL query在 SQL 查询中组合多行
【发布时间】:2016-12-07 01:26:54
【问题描述】:

我有一张这样的数据表

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。谢谢。

【问题讨论】:

标签: sql sql-server tsql


【解决方案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);

返回

EDIT - 生成的 SQL 如下。 (以防万一你不能去 动态)

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

【讨论】:

  • PIVOT 在这种情况下可能是正确的选择。
【解决方案2】:

实现此目的的另一种方法不太优雅,但如果您不想使用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

【讨论】:

    【解决方案3】:

    我会使用条件聚合来做到这一点:

    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 上的索引(如果有的话)。

    【讨论】:

      猜你喜欢
      • 2020-01-27
      • 2022-10-15
      • 1970-01-01
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 2011-01-15
      相关资源
      最近更新 更多