Dynamic Pivot multiple columns in SQL Server

后端 未结 2 930
心在旅途
心在旅途 2021-01-26 11:55

I have a table like this

Id   Name   FromAddress   ToAddress
1    Joey      ABC          JKL
2    Joey      DEF          MNP
3    Joey      GHI          OQR


        
相关标签:
2条回答
  • 2021-01-26 12:33

    ok, I created a temp table to do some testing on. The solution requires an unpivot first. I recommend running with/without the extra test data to get a sense of some other behaviors that surround this solution -- the weirdness that comes with the MAX aggregation and lack of new rows that you might have expected when changing the value in 'name'.

    GL. Hope it helps.

    -------------------------
    -- Some test data here
    CREATE table #addresses ( Id int, Name varchar(5), FromAddress varchar(5), ToAddress varchar(5))
    insert into #addresses(id, Name, FromAddress, ToAddress) Values
    (1,'Joey', 'ABC', 'JKL')
    , (2,'Joey', 'DEF', 'MNO')
    , (3,'Joey', 'GHI', 'PQR')
    , (4,'Spike', 'XXX', 'YYY')
    , (1,'Spike', 'QQQ', 'RRR')
    
    -------------------------
    --  Solution starts here.  create a temp table and unpivot your data into it.
    --  Your initial technique of does not work, PIVOT only supports one aggregation
    
    CREATE table #unpvt(RowColCode varchar(20), vals varchar(20))
    Insert into #unpvt
    SELECT ColCode + '_' + Cast(ID as varchar(2)) as RowColCode, vals
    FROM #addresses a
    UNPIVOT
        (vals for ColCode in (Name,FromAddress,ToAddress)) c
    
    -------------------------
    --  Read the temp table for a column list
    
    declare @ColList nvarchar(max)
    set @ColList = STUFF((
        SELECT distinct ',[' + t.RowColCode + ']'
                FROM #unpvt t
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')
    
    
    -------------------------
    -- 're pivot' the data using your new column list
    
    declare @qry varchar(max)
    set @qry = '
    
    select *
    from
        #unpvt
        PIVOT(
        MAX(vals)
        FOR RowColCode in (' +@ColList +  ') 
        ) rslt
    '
    
    
    execute(@qry)  
    
    0 讨论(0)
  • 2021-01-26 12:52

    I believe the problem is the IN () expression in the PIVOTs. The column list explicitly has to be a list of fields names, not a function and not a list of varchar literals or function values. You've got a REPLACE() function in there. The engine expects to be looking for a field named [REPLACE] and then gets confused by the open parentheses that shows up.

    This is valid (square brackets for emphasis):

    SELECT VendorID, Employee, Orders
    FROM 
       (SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
       FROM pvt) p
    UNPIVOT
       (Orders FOR Employee IN 
          ([Emp1], [Emp2], [Emp3], [Emp4], [Emp5])
    )AS unpvt;
    

    This is not:

    SELECT VendorID, Employee, Orders
    FROM 
       (SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
       FROM pvt) p
    UNPIVOT
       (Orders FOR Employee IN 
          ('Emp1', 'Emp2', 'Emp3', 'Emp4', 'Emp5')
    )AS unpvt;
    

    And this is not valid:

    SELECT VendorID, Employee, Orders
    FROM 
       (SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
       FROM pvt) p
    UNPIVOT
       (Orders FOR Employee IN 
          (REPLACE('Emp1','1','A'), REPLACE('Emp2','2','B'))
    )AS unpvt;
    

    Replace the execute(@query) with a select @query or print @query to see the query your code generated and troubleshoot the syntax in a query analyzer that way. Then work backwards.

    You want to do the REPLACE() at the same level you're building the query. The query that ends up in the @query variable should already have the column names fixed.

    Alternately, you could generate @colsFromLabels, @colsToLabels, @colsFrom and @colsTo with the former two have the 'from' and to bits added and the latter two just being column names.

    Your desired output is a little gross as far as square bracket escaping, too.

    0 讨论(0)
提交回复
热议问题