0

I have a table with column and values as below

enter image description here

How do I fetch the result as in the second tabular column with the DYNAMIC column names as -- first with "prgmg_product_id" and the rest of the column as "source ID 1","source ID 2", "source ID 3"

Jayesh Goyani
  • 11,008
  • 11
  • 30
  • 50
Ramaswamy
  • 79
  • 1
  • 8
  • This has been answered thousands of times around here and the rest of the internet. – Sean Lange Jun 02 '16 at 14:47
  • 3
    Possible duplicate of [SQL Server dynamic PIVOT query?](http://stackoverflow.com/questions/10404348/sql-server-dynamic-pivot-query) – Sean Lange Jun 02 '16 at 14:47
  • 1
    Possible duplicate of [How can I get column names from a table in SQL Server?](http://stackoverflow.com/questions/1054984/how-can-i-get-column-names-from-a-table-in-sql-server) – Pio Jun 02 '16 at 14:48
  • 2
    Really it is 2 step process, every step was answered already. First, Row_number() instances you need to pivot and then build and execute pivot command dynamically. – Serg Jun 02 '16 at 14:53
  • Serg how I can achieve that – Ramaswamy Jun 02 '16 at 14:57
  • @Ramaswamy, follow the duplicate posted by Sean Lange. It answers your question step-by-step. – Tab Alleman Jun 02 '16 at 15:33

2 Answers2

0

I had a little time to I tossed this together. I know that around SO the preference is to use a dynamic pivot. I do not much care for PIVOT in sql server. I find the syntax to be very obtuse. I tend to prefer a cross tab query (also known as conditional aggregation) instead. The added benefit is that this approach is almost always slightly quicker than a dynamic PIVOT.

You also have to realize that more than half of the code posted here is setting up the problem. In the future you should post ddl and sample data in a consumable format like this. It makes it so much easier for us to help.

if OBJECT_ID('tempdb..#Something') is not null
    drop table #Something

create table #Something
(
    prgmg_product_id int,
    source_id_other int
)

insert #Something (prgmg_product_id, source_id_other) values
(3310, 11478),
(3337, 10833),
(3354, 11466),
(4039, 4846),
(4039, 65454),
(4039, 65456)

declare @StaticPortion nvarchar(2000) = 
    'with OrderedResults as
    (
        select *, ROW_NUMBER() over(partition by prgmg_product_id order by source_id_other) as RowNum
        from #Something
    )
    select prgmg_product_id';

declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by prgmg_product_id order by prgmg_product_id desc';

with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)

select @DynamicPortion = @DynamicPortion + 
    ', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then source_id_other end) as SourceID' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <= 
(
    select top 1 Count(*)
    from #Something
    group by prgmg_product_id
    order by COUNT(*) desc
)

declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
exec sp_executesql @SqlToExecute
Sean Lange
  • 33,028
  • 3
  • 25
  • 40
0

To achieve this using Dynamic SQL, the below will help:

CREATE TABLE #Prgmg (
    prgmg_product_id INT
    ,source_id_other INT
    );

INSERT #Prgmg (
    prgmg_product_id
    ,source_id_other
    )
VALUES (3310,11478)
    ,(3337,10833)
    ,(3354,11466)
    ,(4039,4846)
    ,(4039,65454)
    ,(4039,65456);

DECLARE @DYColumns NVARCHAR(1000)
    ,@DYSqlQuery NVARCHAR(4000);

--  CREATE THE COLUMNS REQUIRED
SET @DYColumns = STUFF((
            SELECT DISTINCT ',' 
                    + N'sourceID' 
                    + CAST(ROW_NUMBER() OVER (PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other) AS NVARCHAR(10))    
            FROM #Prgmg
            FOR XML PATH('')
            ), 1, 1, '');

-- CREATE THE DYNAMIC SQL AND ADD IN THE CREATED COLUMNS
SET @DYSqlQuery = '
    SELECT prgmg_product_id,' 
        +   @DYColumns 
        +   ' FROM (
                SELECT prgmg_product_id
                    ,CAST(N''sourceID'' + CAST(ROW_NUMBER() OVER (
                        PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other
                        ) AS NVARCHAR(10)) AS NVARCHAR(100)) AS Col
                    ,source_id_other
                FROM #Prgmg S1
        ) X
        PIVOT(MIN(source_id_other) FOR Col IN (' + @DYColumns + ')) P'

EXECUTE sp_executesql @DYSqlQuery;

Whilst this does offer you the solution, you should spend time understanding the concepts used. Such as the creation of the Columns required using ROW_NUMBER and the how that maps to the use of the PIVOT.

BeaglesEnd
  • 421
  • 3
  • 10