Sql server 在不损失性能的情况下转置SQL列

Sql server 在不损失性能的情况下转置SQL列,sql-server,performance,pivot,transform,Sql Server,Performance,Pivot,Transform,我使用SQL Server 2012。我有两个包含数据的大表,如下所示: tableProjects(为了简单起见减少了列数) tableHours(为了简单起见,过程阶段数减少到3个) 我需要以每个ProcessStage都有一个单独的列的方式选择此数据,因此我将此数据转换为如下所示: SELECT p.ID, p.Name, (SELECT Hours FROM tableHours WHERE ProcessStage = 1 AND ProjectID = p.ID) AS Hours1

我使用SQL Server 2012。我有两个包含数据的大表,如下所示:

tableProjects(为了简单起见减少了列数)

tableHours(为了简单起见,过程阶段数减少到3个)

我需要以每个ProcessStage都有一个单独的列的方式选择此数据,因此我将此数据转换为如下所示:

SELECT p.ID, p.Name,
(SELECT Hours FROM tableHours WHERE ProcessStage = 1 AND ProjectID = p.ID) AS Hours1,
(SELECT Hours FROM tableHours WHERE ProcessStage = 2 AND ProjectID = p.ID) AS Hours2,
(SELECT Hours FROM tableHours WHERE ProcessStage = 3 AND ProjectID = p.ID) AS Hours3
FROM tableProjects p
事实上,我确实得到了我想要的:

| ID | Name     | Hours1 | Hours2 | Hours3 |
| 1  | Project1 | 10     | 20     | 30     |
| 2  | Project2 | 40     | 50     | 60     |
| …  | …        | …      | …      | …      |
| N  | ProjectN | 70     | 80     | 90     |

但就我而言,绩效非常重要,所以我在想,是否有一种更有效的方式来实现这一点。如果你知道的话,能给我看看吗?谢谢。

使用条件聚合来透视数据:

select 
    p.id
  , p.Name
  , Hours1 = max(case when h.ProcessStage = 1 then h.Hours end) 
  , Hours2 = max(case when h.ProcessStage = 2 then h.Hours end) 
  , Hours3 = max(case when h.ProcessStage = 3 then h.Hours end) 
from tableProjects p
  inner join tableHours h
    on h.Projectid = p.id
group by p.id, p.Name

您可以使用动态sql自动生成pivot所需的列,但由于您说过性能非常重要,因此如果可能,最好对其进行硬编码。

考虑tableProjects与多个表连接,并且它有更多自己的列可供选择,例如总共多10列。与我选择这些数据的方式相比,按所有这些列分组是否会降低总体生产率?@B.Sverediuk一点也不。但是既然我没有你的数据,你为什么不测试一下看看呢?检查执行计划和查询统计时间和io。我将尝试您的方法并比较结果。任何对我的数据更有效的方法都会被使用。谢谢
| ID | Name     | Hours1 | Hours2 | Hours3 |
| 1  | Project1 | 10     | 20     | 30     |
| 2  | Project2 | 40     | 50     | 60     |
| …  | …        | …      | …      | …      |
| N  | ProjectN | 70     | 80     | 90     |
select 
    p.id
  , p.Name
  , Hours1 = max(case when h.ProcessStage = 1 then h.Hours end) 
  , Hours2 = max(case when h.ProcessStage = 2 then h.Hours end) 
  , Hours3 = max(case when h.ProcessStage = 3 then h.Hours end) 
from tableProjects p
  inner join tableHours h
    on h.Projectid = p.id
group by p.id, p.Name