How to pivot my data with SQL Server 2005

Question!

I have the following data

alt text

How do I transform it (with SQL Server 2005) into the following format?

alt text

I have a example solution that I came up with but it seems a little clunky. It smells perhaps?

DECLARE @ProductLanguage TABLE
(
    [PRODUCT_ID] int
    , [LANGUAGE] varchar(50)
)

INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'Czech')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'English')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'German')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'Danish')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'Spanish')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'English')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Finnish')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Greek')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Hungarian')
INSERT INTO @ProductLanguage ([PRODUCT_ID],[LANGUAGE]) VALUES (52044,'Hebrew')

SELECT
    PRODUCT_ID
    ,MAX(CASE WHEN [ROW_ID]=1 THEN LANGUAGE ELSE NULL END) As LANG_1
    ,MAX(CASE WHEN [ROW_ID]=2 THEN LANGUAGE ELSE NULL END) As LANG_2
    ,MAX(CASE WHEN [ROW_ID]=3 THEN LANGUAGE ELSE NULL END) As LANG_3
FROM
    (SELECT
        ROW_NUMBER() OVER (PARTITION BY [PRODUCT_ID] ORDER BY [PRODUCT_ID] ASC) AS [ROW_ID]
        , [PRODUCT_ID]
        , [LANGUAGE]
    FROM
        @ProductLanguage) AS Temp
GROUP BY
    [PRODUCT_ID]

The interesting bit is I do not care about the specific Languages displayed in each LANG_* column. Other questions posted here seem to all refer to knowning the pivoted columns by name. But I do not want to name the columns by the languages found.

NOTE: I know I mention the word "pivot" but the best solution for this problem may not involve the PIVOT clause. I just used that word as my question seemed to suggest pivotting data. Maybe a CTE would help with the solution, I do not know. I just know I am not happy about the example solution above.

By : BlackMael


Answers
create table  #ProductLanguage 
(
    PRODUCT_ID int
    , [LANGUAGE] varchar(50)
)

INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'Czech')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'English')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (52035,'German')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'Danish')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'Spanish')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (54001,'English')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Finnish')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Greek')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (70501,'Hungarian')
INSERT INTO #ProductLanguage  ([PRODUCT_ID],[LANGUAGE]) VALUES (52044,'Hebrew')


declare @col as varchar(2000)
declare @query as varchar(4000)

--select language ,@col= replace('[Lang_'+str(row_number() over(order by language))+']',' ','') Lang  from (select distinct language  from #ProductLanguage)p
select  @col = stuff((select distinct '],['+language  from #ProductLanguage for xml path('')),1,2,'')+']' 
print @col

set @query = 'select PRODUCT_ID, '[email protected]+ ' from #ProductLanguage 
pivot (
max(LANGUAGE) for LANGUAGE in ('[email protected]+')
) pvt'
execute(@query)
By : Deena 786


This can be done with a PIVOT, either statically or dynamically.

Static Version the columns are hard-coded (See SQL Fiddle with Demo):

select *
from 
(
  select product_id, language,
    'Lang_' + cast(row_number() over(partition by PRODUCT_ID order by language) as varchar(10)) rn
  from ProductLanguage
) x
pivot
(
  max(language)
  for rn in ([Lang_1], [Lang_2], [Lang_3])
) p

Dynamic Version will get the columns at run-time (See SQL Fiddle With Demo):

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Lang_' + cast(row_number() over(partition by PRODUCT_ID order by language) as varchar(10))) 
                    from ProductLanguage
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT PRODUCT_ID, ' + @cols + ' from 
             (
              select product_id, language,
                ''Lang_'' + cast(row_number() over(partition by PRODUCT_ID order by language) as varchar(10)) rn
              from ProductLanguage
            ) x
            pivot 
            (
                max(language)
                for rn in (' + @cols + ')
            ) p '

execute(@query)
By : bluefeet


You can use the PIVOT() function

SELECT    P.PRODUCT_ID,
          P.Czech,
          P.Other languages
FROM      TABLE AS T
PIVOT     (
              AGGREGATE(LANGUAGE) FOR LANGUAGE IN ([Czech],  ...)
          ) AS P

If you don't name the columns explicitly you are forced into doing tricks as far as I know...

Untested (obviously). See: MSDN

By : Scott


This video can help you solving your question :)
By: admin