Search code examples
sql-serversql-server-2014-expressdynamic-pivot

SQL Server: sort values Into LIKE columns with dynamic pivot


Version: Microsoft SQL Server 2014

I have successfully created a dynamic pivot table (with help), and now I have a question regarding the column names and their values.

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

SELECT @cols = STUFF((SELECT distinct ',' 
                        + QUOTENAME('Component_' + cast(rn as varchar(10))) 
                      FROM dbo.table
                      CROSS APPLY
                          (SELECT row_number() over(partition by UPC order by ComponentNum) rn
                           FROM dbo.table) x
                     FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')

SET @query = 'SELECT UPC, ' + @cols + ' FROM 
             (
                SELECT UPC, ComponentNum,
                  ''Component_''
                    + cast(row_number() over(partition by UPC order by ComponentNum) as varchar(10)) val
                FROM dbo.table) x
            PIVOT
            (
                MAX(ComponentNum)
                FOR val IN (' + @cols + ')
            ) p '

execute(@query)

After the table was pivoted, it created 27 columns of Component_X.

The 27 columns is supposed to represent different kinds of parts that is associated to a unique UPC number. Not all UPCs have 27 kinds of parts.

It seems that depending on what row number the part was listed in the partitioned group of UPC numbers is where it was assigned in the pivot column.

That indicates to me that I need to sort the original data before running the pivot, no? Looking at the result table below, you can see that part number 543 is shown under Component_13, Component_1, and Component_10 for different UPC numbers.

ID          UPC       Component_13      Component_1      Component_10     
------------------------------------------------------------------------
1           123        543                 NULL                345
2           321        345                 543                 765
3           213        654                 345                 NULL         
4           312        765                 NULL                543

My problem is that I cannot allow the part number to float between different columns. If the part number is a "Component_13" type then it needs to stay in that column.

My goal is to have each iteration of Component_X represent a specific kind of part.

Component_1 = Bolts
Component_2 = Nuts
Component_3 = Washers

The other problem is that I also need to enumerate multiple "Bolt" part numbers into their own column for retrieval by another piece of software. Any UPC number could have any number of "Bolts" of different sizes with different part numbers.

End result table could look like:

ID          UPC       Bolt1      Bolt2      Bolt3      Nut1      Nut2     
------------------------------------------------------------------------
1           123        1.5         1         NULL       0.5      .375
2           321        2.0       NULL        NULL       .625      NULL    
3           213        0.25      .875        .375       NULL      NULL         
4           312        NULL      NULL        NULL       1.25      .625

This is probably not possible, but I had to ask if anyone could help with a solution.


Solution

  • You could use REPLICATE to generate a two or more digits number that can be easily ordered.

    create table test(rn varchar(10));
    
    insert into test 
    values ('1'),  ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9'), ('10'), ('11'), ('12');
    
     select num
     from 
         (select 'Component_' + replicate('0',  2 - len(rn)) + rn as num
          from test) x
     order by num;
    

    Result:

     | num          |
     | :----------- |
     | Component_01 |
     | Component_02 |
     | Component_03 |
     | Component_04 |
     | Component_05 |
     | Component_06 |
     | Component_07 |
     | Component_08 |
     | Component_09 |
     | Component_10 |
     | Component_11 |
     | Component_12 |
    

    dbfiddle here