【问题标题】:how to pivot when there are many columns当有很多列时如何旋转
【发布时间】:2019-09-12 20:19:12
【问题描述】:

我想我理解 PIVOT 的概念,但是我在将此查询转换为 PIVOT 时遇到了很多麻烦:

SELECT ID,
CASE WHEN [line] = "1" THEN code ELSE            "" AS one_CODE,
CASE WHEN [line] = "1" THEN name ELSE            "" AS one_NAME,
CASE WHEN [line] = "1" THEN address_line_1 ELSE  "" AS one_ADDRESS_LINE_1,
CASE WHEN [line] = "1" THEN address_line_2 ELSE  "" AS one_ADDRESS_LINE_2,
CASE WHEN [line] = "1" THEN address_city ELSE    "" AS one_ADDRESS_CITY,
CASE WHEN [line] = "1" THEN address_state ELSE   "" AS one_ADDRESS_STATE,
CASE WHEN [line] = "1" THEN address_zip ELSE     "" AS one_ADDRESS_ZIP,
CASE WHEN [line] = "2" THEN code ELSE            "" AS two_CODE,
CASE WHEN [line] = "2" THEN name ELSE            "" AS two_NAME,
CASE WHEN [line] = "2" THEN address_line_1 ELSE  "" AS two_ADDRESS_LINE_1,
CASE WHEN [line] = "2" THEN address_line_2 ELSE  "" AS two_ADDRESS_LINE_2,
CASE WHEN [line] = "2" THEN address_city ELSE    "" AS two_ADDRESS_CITY,
CASE WHEN [line] = "2" THEN address_state ELSE   "" AS two_ADDRESS_STATE,
CASE WHEN [line] = "2" THEN address_zip ELSE     "" AS two_ADDRESS_ZIP,
CASE WHEN [line] = "3" THEN code ELSE            "" AS three_CODE,
CASE WHEN [line] = "3" THEN name ELSE            "" AS three_NAME,
CASE WHEN [line] = "3" THEN address_line_1 ELSE  "" AS three_ADDRESS_LINE_1,
CASE WHEN [line] = "3" THEN address_line_2 ELSE  "" AS three_ADDRESS_LINE_2,
CASE WHEN [line] = "3" THEN address_city ELSE    "" AS three_ADDRESS_CITY,
CASE WHEN [line] = "3" THEN address_state ELSE   "" AS three_ADDRESS_STATE,
CASE WHEN [line] = "3" THEN address_zip ELSE     "" AS three_ADDRESS_ZIP
FROM MYTABLE

期望的结果:

+----+----------+----------+--------------------+--------------------+------------------+-------------------+-----------------+------------+------------+--------------------+--------------------+------------------+-------------------+-----------------+---------------+------------+----------------------+----------------------+--------------------+---------------------+-------------------+
| ID | one_CODE | one_NAME | one_ADDRESS_LINE_1 | one_ADDRESS_LINE_2 | one_ADDRESS_CITY | one_ADDRESS_STATE | one_ADDRESS_ZIP |  two_CODE  |  two_NAME  | two_ADDRESS_LINE_1 | two_ADDRESS_LINE_2 | two_ADDRESS_CITY | two_ADDRESS_STATE | two_ADDRESS_ZIP |  three_CODE   | three_NAME | three_ADDRESS_LINE_1 | three_ADDRESS_LINE_2 | three_ADDRESS_CITY | three_ADDRESS_STATE | three_ADDRESS_ZIP |
+----+----------+----------+--------------------+--------------------+------------------+-------------------+-----------------+------------+------------+--------------------+--------------------+------------------+-------------------+-----------------+---------------+------------+----------------------+----------------------+--------------------+---------------------+-------------------+
|  1 | a        | b        | c                  | d                  |                  |                   |                 | bluecross  | blueshield |                    |                    |                  |                   |                 |               |            |                      |                      |                    |                     |                   |
|  2 | anthem   | myerland | 234                |                    |                  |                   |                 |            |            |                    |                    |                  |                   |                 |               |            |                      |                      |                    |                     |                   |
|  3 | anthem   | b        | 234 albin          |                    |                  |                   |                 | blueshield |            |                    |                    |                  |                   |                 | hartford life |            |                      |                      |                    |                     |                   |
+----+----------+----------+--------------------+--------------------+------------------+-------------------+-----------------+------------+------------+--------------------+--------------------+------------------+-------------------+-----------------+---------------+------------+----------------------+----------------------+--------------------+---------------------+-------------------+

如何为每个 ID 只输出 1 条记录?

【问题讨论】:

  • 使用聚合函数,例如max(case when ...
  • 看看我的回答有没有帮助

标签: sql tsql pivot-table


【解决方案1】:

使用聚合:

select id,
       MAX(CASE WHEN [line] = 1 THEN code END) AS one_CODE,
       MAX(CASE WHEN [line] = 1 THEN name END) AS one_NAME,
       . . .
from t
group by id;

注意事项:

  • SQL Server 使用双引号来分隔标识符,而不是字符串。此查询不需要双引号。
  • line 可能是一个数字,所以比较值应该是一个数字。
  • 这将返回 NULL 而不是空字符串。
  • 我认为尝试使用 pivot 进行此查询没有任何好处。

【讨论】:

    【解决方案2】:

    如果您可以容忍性能,请查找CHOOSE 函数。我已经在下面实现了。

        SELECT ID,
        MAX(CHOOSE([line],code)) AS one_CODE,
        MAX(CHOOSE([line],name)) AS one_name,
        MAX(CHOOSE([line],address_line_1)) AS one_address_[line]_1 ,
        MAX(CHOOSE([line],address_line_2)) AS one_address_[line]_2,
        MAX(CHOOSE([line],address_city)) AS one_address_city ,
        MAX(CHOOSE([line],address_state)) AS one_address_state,
        MAX(CHOOSE([line],address_zip)) AS one_address_zip ,
        MAX(CHOOSE([line]-1,code)) AS two_CODE,
        MAX(CHOOSE([line]-1,name)) AS two_name,
        MAX(CHOOSE([line]-1,address_line_1)) AS two_address_[line]_1 ,
        MAX(CHOOSE([line]-1,address_line_2)) AS two_address_[line]_2,
        MAX(CHOOSE([line]-1,address_city)) AS two_address_city,
        MAX(CHOOSE([line]-1,address_state)) AS two_address_state,
        MAX(CHOOSE([line]-1,address_zip)) AS two_address_zip,
        MAX(CHOOSE([line]-2,code)) AS three_CODE,
        MAX(CHOOSE([line]-2,name)) AS three_name,
        MAX(CHOOSE([line]-2,address_line_1)) AS three_address_[line]_1 ,
        MAX(CHOOSE([line]-2,address_line_2)) AS three_address_[line]_2,
        MAX(CHOOSE([line]-2,address_city)) AS three_address_city,
        MAX(CHOOSE([line]-2,address_state)) AS three_address_state,
        MAX(CHOOSE([line]-2,address_zip)) AS three_address_zip
        FROM MYTABLE
        GROUP BY ID;
    

    【讨论】:

      【解决方案3】:

      一个不错的自联接怎么样,在我深入回答之前,我先说明我的假设,表中有 7 列,加上与行相关的键 ID。如果是这样的话,你所要做的就是

      select a.ID
        , a.CODE as one_code
        , a.name as One_name
        , a.address_line_1 as one_address_line_1
        , a.ADDRESS_LINE_2 as one_ADDRESS_LINE_2
        , a.City as One_city
        , a.state as One_state
        , a.zip as one_zip
        , a.CODE as one_code
        , b.name as two_name
        , b.address_line_1 as two_address_line_1
        , b.ADDRESS_LINE_2 as two_ADDRESS_LINE_2
        , b.City as two_city
        , b.state as two_state
        , b.zip as two_zip
        , c.name as three_name
        , c.address_line_1 as three_address_line_1
        , c.ADDRESS_LINE_2 as three_ADDRESS_LINE_2
        , c.City as three_city
        , c.state as three_state
        , c.zip as three_zip
      from mytable a
        left outer join mytable b on a.id = b.id and b.line = 2
        left outer join mytable c on c.id = a.id and c.line = 3
      where a.line = 1
      

      所以我们所做的就是所谓的自连接,因为这三组数据都在同一个表中,所以我们将具有不同行值的行别名为单独的表,然后将它们左外连接。我们使用左外连接,因为看起来只有第 1 行是必需的,第 2 行和第 3 行是可选的。希望这会有所帮助:)

      【讨论】:

      • 尽管如此,您在左表中的行数仍然与以前相同
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      相关资源
      最近更新 更多