【问题标题】:Simple SQL Query -简单的 SQL 查询 -
【发布时间】:2013-08-26 22:22:40
【问题描述】:

我在 SQLServer 表中有这样的数据:

ID   Name   Year   Value
--   ----   ----   -----
2    Ted    2013   2000
2    Ted    2012   1000

我需要视图语法来输出这个:

ID    Name    Yr1    Value1    Yr2    Value2
--    ----    ---    ------    ---    ------ 
2     Ted     2013   2000      2012   1000

如果可能,不要使用游标。 任何线索都会很棒。

【问题讨论】:

标签: sql sql-server tsql pivot unpivot


【解决方案1】:

在 SQL Server 中,您可以通过多种方式获得结果。

如果您的值数量有限,那么您可以轻松地对结果进行硬编码。获得结果的一种方法是使用带有 CASE 表达式的聚合函数:

select d.id,
  d.name,
  max(case when seq = 1 then year end) year1,
  max(case when seq = 1 then value end) value1,
  max(case when seq = 2 then year end) year2,
  max(case when seq = 2 then value end) value2
from
(
  select id, name, year, value,
    row_number() over(partition by id order by year desc) seq
  from yourtable
) d
group by d.id, d.name;

SQL Fiddle with Demo。如果你想使用PIVOT 函数,那么我建议首先unpivoting yearvalue 列中的数据。 unpivot 过程将多列转换为多行。您可以使用 UNPIVOT 函数,但在我的示例中,我使用 CROSS APPLY 和 UNION ALL 查询,代码是:

select t.id, t.name, 
  col = c.col+cast(seq as varchar(4)), 
  c.val
from
(
  select id, name, year, value,
    row_number() over(partition by id order by year desc) seq
  from yourtable
) t
cross apply
(
  select 'year', t.year union all
  select 'value', t.value 
) c (col, val)

SQL Fiddle with Demo。这会将您的多列转换为具有多行的稍微不同的格式:

| ID | NAME |    COL |  VAL |
|  2 |  Ted |  year1 | 2013 |
|  2 |  Ted | value1 | 2000 |
|  2 |  Ted |  year2 | 2012 |
|  2 |  Ted | value2 | 1000 |

然后您可以在此应用 PIVOT 函数以获得最终想要的结果:

select id, name, year1, value1, year2, value2
from 
(
  select t.id, t.name, 
    col = c.col+cast(seq as varchar(4)), 
    c.val
  from
  (
    select id, name, year, value,
      row_number() over(partition by id order by year desc) seq
    from yourtable
  ) t
  cross apply
  (
    select 'year', t.year union all
    select 'value', t.value 
  ) c (col, val)
) d
pivot
(
  max(val)
  for col in (year1, value1, year2, value2)
) piv;

SQL Fiddle with Demo。最后,如果您想要将未知数量的值从行转换为列,那么您可以在存储过程中使用动态 SQL:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT  ',' + QUOTENAME(col+cast(seq as varchar(4))) 
                    from 
                    (
                      select row_number() over(partition by id order by year desc) seq
                      from yourtable
                    ) d
                    cross apply 
                    (
                      select 'year', 1 union all
                      select 'value', 2
                    ) c (col, so)
                    group by seq, col, so
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT id, name,' + @cols + ' 
             from 
             (
               select t.id, t.name, 
                  col = c.col+cast(seq as varchar(4)), 
                  c.val
                from
                (
                  select id, name, year, value,
                    row_number() over(partition by id order by year desc) seq
                  from yourtable
                ) t
                cross apply
                (
                  select ''year'', t.year union all
                  select ''value'', t.value 
                ) c (col, val)
            ) x
            pivot 
            (
                max(val)
                for col in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SQL Fiddle with Demo。所有版本都会给出结果:

| ID | NAME | YEAR1 | VALUE1 | YEAR2 | VALUE2 |
|  2 |  Ted |  2013 |   2000 |  2012 |   1000 |

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 2021-07-09
    相关资源
    最近更新 更多