带有字符串字段的SQL Pivot表

时间:2017-03-01 17:46:43

标签: sql-server pivot-table

我是SQL Pivot的新手,所以我想详细解释一下。我的表格如下:

PID   | NAME |  PlateNumber  |  COUNTRY|
------------------------------------------
111   | Alex |  ab123456     |  GB      |
------------------------------------------
111   | Alex |  fe123344     |  ES      |
------------------------------------------
111   | Alex |  r223456e     |  US      |
------------------------------------------
112   | Simon |  t22er563    |  GB      |
------------------------------------------
112   | Simon |  q32345ke    |  DE      |
------------------------------------------
113   | Ben   |  ve923456    |  IT      |
------------------------------------------

我希望得到以下格式的结果:

PID |NAME |PlateNumber1|PlateNumber2| PlateNumber3|COUNTRY1| COUNTRY2| COUNTRY3|
--------------------------------------------------------------------------------
111 | Alex |  ab123456 |  fe123344  | r223456e    | GB     | ES      | US     |
--------------------------------------------------------------------------------
112 | Simon |  t22er563|  q32345ke  |             | GB     | DE      |        |
--------------------------------------------------------------------------------
113 | Ben   |  ve923456|            |             | IT     |         |        |
--------------------------------------------------------------------------------

你能帮帮我吗?

提前谢谢!

3 个答案:

答案 0 :(得分:1)

使用PIVOT

with your_table(PID   , NAME  ,  PlateNumber ,  Country) as (
    select 111   , 'Alex'  ,  'ab123456'   ,  'GB' union all
    select 111   , 'Alex'  ,  'fe123344'   ,  'ES' union all
    select 111   , 'Alex'  ,  'r223456e'   ,  'US' union all
    select 112   , 'Simon' ,  't22er563'   ,  'GB' union all
    select 112   , 'Simon' ,  'q32345ke'   ,  'DE' union all
    select 113   , 'Ben'   ,  've923456'   ,  'IT'
)
select pid,
    name,
    max(PlateNumber1) PlateNumber1,
    max(PlateNumber2) PlateNumber2,
    max(PlateNumber3) PlateNumber3,
    max(Country1) Country1,
    max(Country2) Country2,
    max(Country3) Country3
from (
    select *,
        'Country' + cast(row_number() over (
                partition by PID order by pnum
                ) as varchar(30)) cn
    from (
        select t.*,PlateNumber pnum,
            'PlateNumber' + cast(row_number() over (
                    partition by PID order by PlateNumber
                    ) as varchar(30)) pn
        from your_table t
        ) t
    pivot(max(PlateNumber) for pn in ([PlateNumber1], [PlateNumber2], [PlateNumber3])) x
    ) t
pivot(max(Country) for cn in ([Country1], [Country2], [Country3])) x
group by pid,
    name;

Demo

答案 1 :(得分:1)

传统的交叉表/条件聚合版本就是这样:

测试设置:http://rextester.com/SKMUL25726

select 
    pid
  , name
  , PlateNumber1 = max(case when rn = 1 then PlateNumber end)
  , PlateNumber2 = max(case when rn = 2 then PlateNumber end)
  , PlateNumber3 = max(case when rn = 3 then PlateNumber end)
  , Country1 = max(case when rn = 1 then Country end)
  , Country2 = max(case when rn = 2 then Country end)
  , Country3 = max(case when rn = 3 then Country end)
from (
  select t.*
    , rn=row_number() over (partition by PID order by platenumber) 
  from t
  ) as t
group by pid, name

返回:

+-----+-------+--------------+--------------+--------------+----------+----------+----------+
| pid | name  | PlateNumber1 | PlateNumber2 | PlateNumber3 | Country1 | Country2 | Country3 |
+-----+-------+--------------+--------------+--------------+----------+----------+----------+
| 111 | Alex  | ab123456     | fe123344     | r223456e     | GB       | ES       | US       |
| 113 | Ben   | ve923456     | NULL         | NULL         | IT       | NULL     | NULL     |
| 112 | Simon | q32345ke     | t22er563     | NULL         | DE       | GB       | NULL     |
+-----+-------+--------------+--------------+--------------+----------+----------+----------+

答案 2 :(得分:0)

如果PlateNumber计数未固定为PID,则可以使用动态语句。

    CREATE  TABLE #tt(PID INT,[Name] VARCHAR(10),PlateNumber VARCHAR(10),Country VARCHAR(5))
    INSERT INTO #tt
    select 111   , 'Alex'  ,  'ab123456'   ,  'GB' union all
    select 111   , 'Alex'  ,  'fe123344'   ,  'ES' union all
    select 111   , 'Alex'  ,  'r223456e'   ,  'US' union all
    select 112   , 'Simon' ,  't22er563'   ,  'GB' union all
    select 112   , 'Simon' ,  'q32345ke'   ,  'DE' union all
    select 113   , 'Ben'   ,  've923456'   ,  'IT'

    DECLARE @SQL VARCHAR(max),@col VARCHAR(max)
    ----   Get the max line count of all the PID
    DECLARE @MaxNumber INT =0
    SELECT @MaxNumber=CASE WHEN COUNT(0)>@MaxNumber THEN count(0) ELSE @MaxNumber END  FROM #tt AS t GROUP BY t.Name,t.PID
    PRINT @MaxNumber
    SELECT @col=ISNULL(@col+',','')+'PlateNumber'+LTRIM(sv.number)+',Country'+LTRIM(sv.number)
    FROM  master.dbo.spt_values AS sv WHERE sv.type='P' AND sv.number BETWEEN 1 AND @MaxNumber
    PRINT @col
    SET @SQL='
    SELECT * FROM (
        SELECT pid,[name],c.col_value,c.col_title+LTRIM(ROW_NUMBER()OVER(PARTITION BY t.PID,[name],c.col_title ORDER BY (SELECT 0))) AS col_title FROM #tt AS t
         CROSS APPLY(VALUES(''PlateNumber'',t.PlateNumber),(''Country'',t.Country))c(col_title,col_value)
    ) AS t
    PIVOT(MAX(col_value) FOR col_title IN ('+@col+')) p'
    EXEC(@SQL)
pid         name       PlateNumber1 Country1   PlateNumber2 Country2   PlateNumber3 Country3
----------- ---------- ------------ ---------- ------------ ---------- ------------ ----------
111         Alex       r223456e     GB         fe123344     ES         ab123456     US
113         Ben        ve923456     IT         NULL         NULL       NULL         NULL
112         Simon      q32345ke     DE         t22er563     GB         NULL         NULL