【问题标题】:How to pivot data in SQL Server 2008 to get the desired results?如何在 SQL Server 2008 中透视数据以获得所需的结果?
【发布时间】:2015-11-30 19:14:04
【问题描述】:

在过去(herehere)得到了这个主题的非常好的答案之后。似乎我仍然无法理解这个枢轴的东西(我也很长时间没有使用它)。

所以希望有人(再次)能够告诉我如何将数据转换为所需的格式:

给定数据:

ID | Label | Occurences | RangeBegin | RangeEnd | Unit
---+-------+------------+------------+----------+--------
1  | One   | 0          | -1000      | 0        | m
1  | One   | 5          | 0          | 10       | m
1  | One   | 8          | 10         | 20       | m
1  | One   | 6          | 20         | 30       | m
1  | One   | 15         | 30         | 40       | m
1  | One   | 0          | 40         | 1000     | m
2  | One   | 0          | -1000      | 0        | m
2  | One   | 2          | 0          | 10       | m
2  | One   | 13         | 10         | 20       | m
2  | One   | 27         | 20         | 30       | m
2  | One   | 5          | 30         | 40       | m
2  | One   | 0          | 40         | 1000     | m
1  | Two   | 0          | -1000      | 0        | kg
1  | Two   | 4          | 0          | 2        | kg
1  | Two   | 6          | 2          | 4        | kg
1  | Two   | 1          | 4          | 6        | kg
1  | Two   | 0          | 6          | 1000     | kg
2  | Two   | 0          | -1000      | 0        | kg
2  | Two   | 8          | 0          | 2        | kg
2  | Two   | 1          | 2          | 4        | kg
2  | Two   | 3          | 4          | 6        | kg
2  | Two   | 0          | 6          | 1000     | kg

想要的结果:

ID | One | OneRangeBegin | OneRangeEnd | OneUnit | Two  | TwoRangeBegin | TwoRangeEnd | TwoUnit
---+-----+---------------+-------------+---------+------+---------------+-------------+----------
 1 | 0   | -1000         | 0           | m       | 0    | -1000         | 0           | kg
 1 | 5   | 0             | 10          | m       | 4    | 0             | 2           | kg
 1 | 8   | 10            | 20          | m       | 6    | 2             | 4           | kg
 1 | 6   | 20            | 30          | m       | 1    | 4             | 6           | kg
 1 | 15  | 30            | 40          | m       | 0    | 6             | 1000        | kg
 1 | 0   | 40            | 1000        | m       | null | null          | null        | null
 2 | 0   | -1000         | 0           | m       | 0    | -1000         | 0           | kg
 2 | 2   | 0             | 10          | m       | 8    | 0             | 2           | kg
 2 | 13  | 10            | 20          | m       | 1    | 2             | 4           | kg
 2 | 27  | 20            | 30          | m       | 3    | 4             | 6           | kg
 2 | 5   | 30            | 40          | m       | 0    | 6             | 1000        | kg
 2 | 0   | 40            | 1000        | m       | null | null          | null        | null

为了让工作更轻松,我把上面的数据放在SqlFiddle

【问题讨论】:

  • 您需要查看 unpivot 和 pivot 。您是否尝试过任何代码来获得解决方案?
  • 发布您的查询尝试以及它出了什么问题。错误或意外结果?

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


【解决方案1】:

我认为可以通过这样做来实现:

  1. 根据标签拆分表格
  2. 通过对 ID 进行分区并根据 RangeBegin 对其进行排列来对每个表进行排名。 ROW_NUMBER() OVER(PARTITION BY ID ORDER BY RangeBegin)
  3. 完全加入两个表的 ID 和 Rank

SQL Fiddle

SELECT 
 A.ID AS ID
,A.Occurences AS One
,A.RangeBegin AS OneRangeBegin
,A.RangeEnd AS OneRangeEnd
,A.Unit AS OneUnit
,B.Occurences AS Two
,B.RangeBegin AS TwoRangeBegin
,B.RangeEnd AS TwoRangeEnd
,B.Unit AS TwoUnit


FROM
(select
*, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY RangeBegin) Rank
from
AvailableData
wHere Label = 'One') A
FULL JOIN
(select
*, ROW_NUMBER() OVER(PARTITION BY ID  ORDER BY RangeBegin) Rank
from
AvailableData
Where Label = 'Two' ) B
ON A.ID = B.ID
AND A.Rank = B.Rank
ORDER BY ISNULL(A.ID, B.ID), ISNULL(A.Rank, B.Rank)

【讨论】:

    【解决方案2】:

    我也一直难以将头绕在枢轴上。出于这个原因,我倾向于使用聚合 CASE 方法而不是 PIVOT,因为我发现它更容易推理(而且更灵活)。基本上,您需要将问题分解为多个步骤。

    1. 确定数据的分组方式 - 例如,按 ID、RangeBegin、RangeEnd
    2. 确定所有列的内容以及它们的来源
    3. 为每个单独的列编写一个聚合的 CASE 语句 - 注意:您必须确保每个输出都是明确的,否则会丢失结果

    聚合 CASE 枢轴的总体布局如下:

    SELECT
      grouped columns
      ,MAX(CASE WHEN condition THEN column END) as ColumnName
      ,...
    FROM
      Table
    GROUP BY grouped columns
    

    关键是上面的条件会识别每一列的来源。例如,当Label 列是One 时,OneUnit 列显然来自Unit 列,那么就是:

    MAX(CASE WHEN Label='One' THEN Unit END) as OneUnit
    

    这很容易应用于您的特定示例,除了没有明显的方法将行从一到二关联在一起,因为您将不同的范围组合在一起。在构建实际的数据透视查询之前,您需要确定一个明确的规则以将数据透视表中的行组合在一起,这应该非常简单(这会生成额外的行,因为 One 和 Two 集合之间的范围不同):

    select
      D.ID, D.RangeBegin, D.RangeEnd
      ,MAX(CASE WHEN Label='One' THEN D.Occurences END) as One
      ,MAX(CASE WHEN Label='One' THEN D.RangeBegin END) as OneRangeBegin
      ,MAX(CASE WHEN Label='One' THEN D.RangeEnd END) as OneRangeEnd
      ,MAX(CASE WHEN Label='One' THEN D.Unit END) as OneUnit
      ,MAX(CASE WHEN Label='Two' THEN D.Occurences END) as Two
      ,MAX(CASE WHEN Label='Two' THEN D.RangeBegin END) as TwoRangeBegin
      ,MAX(CASE WHEN Label='Two' THEN D.RangeEnd END) as vRangeEnd
      ,MAX(CASE WHEN Label='Two' THEN D.Unit END) as TwoUnit
    from
      AvailableData D
    group by
      D.ID, D.RangeBegin, D.RangeEnd
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      • 2018-02-09
      • 1970-01-01
      • 2014-09-09
      • 2022-09-27
      相关资源
      最近更新 更多