SQL Server透视查询替代或优化

时间:2016-09-13 22:03:29

标签: sql sql-server tsql sql-server-2012 pivot

所以我有这些表:

-- tbl_obs
id  lat  lon   created
-------------------------
1   1.2  -2.1  2002-08-03
2   1.9  -5.5  2002-08-03
3   1.5  -4.1  2002-08-03

-- tbl_obsdata
id  name         value     obs_id
---------------------------------
1   gender       Male       1
2   type         Type I     1
3   description  Some desc  1
4   gender       Female     2
5   type         Type II    2
6   description  Some desc  2
7   gender       Female     3
8   type         Type II    3
9   description  Some desc  3

我想要一个将两个表中的数据组合在一起的查询:

lat  lon   created     gender  type  description
------------------------------------------------
1.2  -2.1  2002-08-03  Male   Type I  Some desc
1.9  -5.5  2002-08-03  Female Type I  Some desc
1.5  -4.1  2002-08-03  Male   Type II Some desc

我知道我可以用像这样的支点来做到这一点:

with cte as (
 select obsdata.name, obsdata.value, obs.lat, obs.lon, obs.created
 from obsdata
 left join obs on obs.id = obsdata.obs_id
)
select lat, lon, created, gender, type, description
from cte
pivot(
 max(value)
 for [name] in (gender, type, description)
) as pvt

到目前为止,这会返回结果(我认为),但我有大约一百万行,而且运行速度非常慢。任何替代方法来实现这一目标会更快?我使用的是SQL Server 2012。

2 个答案:

答案 0 :(得分:4)

另一种选择是

Select A.lat
      ,A.lon
      ,A.created
      ,gender      = max(IIF(B.name='gender',B.value,null))
      ,type        = max(IIF(B.name='type',B.value,null))
      ,description = max(IIF(B.name='description',B.value,null))
 From  tbl_obs A
 Join  tbl_obsdata B on (A.id=B.obs_id)
 Group By A.lat
      ,A.lon
      ,A.created

返回

lat lon     created     gender  type    description
1.2 -2.1    2002-08-03  Male    Type I  Some desc
1.5 -4.1    2002-08-03  Female  Type II Some desc
1.9 -5.5    2002-08-03  Female  Type II Some desc

答案 1 :(得分:3)

首先优化枢轴,然后优化join。我认为SQL Server为枢纽做了一个合理的工作,所以从:

开始
select obs_id,  gender, type, description
from tbl_obsdata
pivot (max(value) for [name] in (gender, type, description)
      ) as pvt;

然后,在tbl_obsdata(obs_id, name, value)上创建索引。这应该相当快。

如果是,那么加入其余部分:

with cte as (
      select obs_id,  gender, type, description
      from tbl_obsdata
      pivot (max(value) for [name] in (gender, type, description)
            ) as pvt
    )
select obs.lat, obs.lon, obs.created,
       cte.gender, cte.type, cte.description
from cte join
     obs
     on obs.id = cte.obs_id;

编辑:

我也想知道这会怎么样:

select obs.lat, obs.lon, obs.created, od.gender, od.type, od.description
from obs cross apply
     (select max(case when name = 'gender' then value end) as gender,
             max(case when name = 'type' then value end) as type,
             max(case when name = 'description' then value end) as description

      from tbl_obsdata od
      where od.obs_id = obs.id
     ) od;

这也需要tbl_obsdata(obs_id, name, value)上的索引。