Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Wie konvertiere ich Zeilenwerte in Spalten mit dynamischer Spaltenanzahl?

Mein Vorschlag, wann immer Sie mit PIVOT arbeiten, ist, die Abfrage immer zuerst mit den fest codierten Werten zu schreiben, dann können Sie die Abfrage einfach in eine dynamische Lösung umwandeln.

Da Sie mehrere Werte von columnC haben werden die in Spalten konvertiert werden, dann müssen Sie sich die Verwendung von row_number() ansehen Fensterfunktion zum Generieren einer eindeutigen Sequenz für jede columnc basierend auf den Werten von columnA und columnB .

Der Ausgangspunkt für Ihre Abfrage ist:

select [ColumnA],
  [ColumnB],
  [ColumnC],
  'SampleTitle'+
  cast(row_number() over(partition by columna, columnb
                          order by columnc) as varchar(10)) seq
from DataSource;

Siehe Demo. Diese Abfrage generiert die Liste der neuen Spaltennamen SampleTitle1 , etc:

| COLUMNA | COLUMNB | COLUMNC |          SEQ |
|---------|---------|---------|--------------|
|    5060 |    1006 |  100118 | SampleTitle1 |
|    5060 |    1006 |  100119 | SampleTitle2 |
|    5060 |    1006 |  100120 | SampleTitle3 |

Sie können dann den Pivot auf columnC anwenden mit den neuen Spaltennamen, die in seq aufgelistet sind :

select columnA, columnB, 
  SampleTitle1, SampleTitle2, SampleTitle3
from
(
   select [ColumnA],
    [ColumnB],
    [ColumnC],
    'SampleTitle'+
      cast(row_number() over(partition by columna, columnb
                              order by columnc) as varchar(10)) seq
   from DataSource
) d
pivot
(
  max(columnc)
  for seq in (SampleTitle1, SampleTitle2, SampleTitle3)
) piv;

Siehe SQL Fiddle mit Demo.

Sobald Sie die richtige Logik haben, können Sie die Daten in dynamisches SQL konvertieren. Der Schlüssel hier ist die Generierung der Liste der neuen Spaltennamen. Normalerweise verwende ich FOR XML PATH dafür ähnlich wie:

select STUFF((SELECT distinct ',' + QUOTENAME(seq) 
                from
                (
                  select 'SampleTitle'+
                    cast(row_number() over(partition by columna, columnb
                                            order by columnc) as varchar(10)) seq
                  from DataSource
                ) d
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

Siehe Demo. Sobald Sie die Liste der Spaltennamen haben, generieren Sie Ihre auszuführende SQL-Zeichenfolge. Der vollständige Code lautet:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(seq) 
                    from
                    (
                      select 'SampleTitle'+
                        cast(row_number() over(partition by columna, columnb
                                                order by columnc) as varchar(10)) seq
                      from DataSource
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT columnA, ColumnB,' + @cols + ' 
             from 
             (
               select [ColumnA],
                [ColumnB],
                [ColumnC],
                ''SampleTitle''+
                  cast(row_number() over(partition by columna, columnb
                                          order by columnc) as varchar(10)) seq
               from DataSource
            ) x
            pivot 
            (
                max(columnc)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

Siehe SQL-Fiddle mit Demo. Diese geben ein Ergebnis:

| COLUMNA | COLUMNB | SAMPLETITLE1 | SAMPLETITLE2 | SAMPLETITLE3 |
|---------|---------|--------------|--------------|--------------|
|    5060 |    1006 |       100118 |       100119 |       100120 |
|    5060 |    1007 |       100121 |       100122 |       (null) |
|    5060 |    1012 |       100123 |       (null) |       (null) |