Как развернуть несколько столбцов SQLServer

В моем приложении я использовал значения описания продукта магазина следующим образом:

ID  BILLNO    CUS_NAME     DATE         TOT_BAL  S1 S2  S3  S4      D1  D2  D3  D4      Q1  Q2  Q3  Q4      U1  U2  U3  U4      T1   T2     T3  T4  TOTAL   CUSCODE
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
29  1         XXX          Apr-03-2017  1932     1  2   3   NULL    AAA BBB CCC NULL    6   30  6   NULL    80  35  67  NULL    480  1050   402 0   1932    DF
40  2         YYYY         Apr-04-2017  6454     1  2   3   NULL    AAA DDD FFF NULL    30  24  50  NULL    80  96  35  NULL    2400 2304  1750 0   6454    MQ    
-------------------------------------------------------------------------------------------------------------------------------------------------------------------

Я переношу свое приложение на новейшие технологии, поэтому я реструктурирую таблицы mt, чтобы избежать осложнений. Итак, я хочу, чтобы результат адаптировал мою новую таблицу следующим образом:

  BILLNO  CUS_NAME  DATE         TOT_BAL SNO  Pdt  QTY  Unit  Tot  CUSCODE
  1       XXX       Apr-03-2017  1932    1    AAA  6    80    480  DF
  1       XXX       Apr-03-2017  1932    2    BBB  30   35   1050  DF
  1       XXX       Apr-03-2017  1932    3    CCC  6    67    402  DF
  2       YYY       Apr-04-2017  6454    1    AAA  30   80   2400  MQ
  2       YYY       Apr-04-2017  6454    2    DDD  24   96   2304  MQ
  2       YYY       Apr-04-2017  6454    3    FFF  50   35   1750  MQ

Я попробовал запрос ниже, но он дает неверный результат:

Мне не нужны нулевые значения. Мне просто нужно иметь только действительные данные. Например, S4, D4, Q4 являются нулевыми значениями, поэтому вывод должен игнорировать это.

SELECT BILLNO, CUS_NAME,SNOA,SNO,PDTA,PDT
FROM [tmpFormat]
UNPIVOT
(
  SNO
  FOR SNOA IN (S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,S15,S16,S17)
) UnPIV
UNPIVOT
(
  PDT
  FRO PDTA IN (D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16,D17)
) UnPiv1;

person Vignesh Kumar A    schedule 01.06.2017    source источник
comment
Я бы предположил, что у вашей целевой таблицы есть свои проблемы - вы храните данные, которые должны быть одинаковыми в нескольких строках. Мое собственное предложение состояло бы в том, чтобы использовать две таблицы - одну для заголовка (общие значения) и одну для позиций. И прекратите хранить вычисляемые данные (TOT_BAL), если вы не можете продемонстрировать производительность, необходимую для их сохранения.   -  person Damien_The_Unbeliever    schedule 01.06.2017
comment
@Damien_The_Unbeliever Да, у меня есть две таблицы, как вы предложили, но здесь я упомянул только подробную таблицу. Я буду хранить общую информацию только в таблице заголовков. Пожалуйста, помогите мне   -  person Vignesh Kumar A    schedule 01.06.2017


Ответы (3)


ПОПРОБУЙТЕ ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ

SELECT BILLNO, CUS_NAME, UnP.SNOA, UnP.PDTA --,..
FROM [tmpFormat]
CROSS APPLY
( SELECT S1 AS SNOA, D1 as PDTA --,..
  UNION ALL
  SELECT S2 AS SNOA, D2 as PDTA --,.. 
 -- ..
) UnP
person Serg    schedule 01.06.2017

Разворот динамического запроса:

Использование Sys.Columns and Stuff (динамические запросы) для конкатенации | группировка значений нескольких столбцов (необходимо добавить) в один столбец.

Пример S1, S2, S3...... как SNO

Позже динамический запрос обрабатывается с помощью Unpivot для преобразования данных нескольких столбцов в одну строку. Пример D1, D2, D3... в столбце PDT с идентификатором для сопоставления со статическими данными.

Результаты динамических запросов сохраняются в переменных таблицы для последующей обработки.

Созданные табличные переменные используются с CTE для объединения несводных данных со статическими данными для получения окончательного результата.

    If OBJECT_ID('UnpivotData','u') is not null
     Drop table UnPivotData
    go
    Create table UnPivotData
    (
    Id int,
    BILLNO int,
    Cus_Name varchar(10),
    [Date] date,
    Tot_Bal Int,
    S1 smallint,
    S2 smallint,
    S3 smallint,
    S4 smallint,
    D1 varchar(3),
    D2 varchar(3),
    D3 varchar(3),
    D4 varchar(3),
    Q1 smallint,
    Q2 smallint,
    Q3 smallint,
    Q4 smallint,
    U1 smallint,
    U2 smallint,
    U3 smallint,
    U4 smallint,
    T1 smallint,
    T2 smallint,
    T3 smallint,
    T4 smallint,
    Total int,
    CusCode varchar(2)
    )

    insert into UnPivotData
    Select 29, 1, 'XXX', '03-04-2017', 1932, 1, 2, 3, NULL, 'AAA', 'BBB', 'CCC', NULL, 6, 30, 6, NULL, 80, 35, 67, NULL, 480, 1050, 402, 0, 1932, 'DF'
    union
    Select 40, 2,'YYY', '04-04-2017', 6454, 1, 2, 3, NULL, 'AAA', 'DDD', 'FFF', NULL, 30, 24, 50, NULL, 80, 96, 35, NULL, 2400, 2304, 1750, 0, 6454, 'MQ'


    DECLARE @SNO AS NVARCHAR(MAX)='',@PDT  AS NVARCHAR(MAX)='',@QTY  AS NVARCHAR(MAX)='', @UNIT  AS NVARCHAR(MAX)='', @TOT  AS NVARCHAR(MAX)=''

    SET @SNO = STUFF((SELECT distinct ',' + QuoteName(C.name)
                from sys.tables T join sys.columns C on T.object_id=C.object_id and T.object_id=OBJECT_ID('UnPivotData','U') and C.Name like'S'+'[0-9]%'
                 FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')
    SET @PDT = STUFF((SELECT distinct ',' + QuoteName(C.name)
                from sys.tables T join sys.columns C on T.object_id=C.object_id and T.object_id=OBJECT_ID('UnPivotData','U') and C.Name like'D'+'[0-9]%'
                 FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')
    SET @QTY = STUFF((SELECT distinct ',' + QuoteName(C.name)
               from sys.tables T join sys.columns C on T.object_id=C.object_id and T.object_id=OBJECT_ID('UnPivotData','U') and C.Name like'Q'+'[0-9]%'
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')
    SET @UNIT = STUFF((SELECT distinct ',' + QuoteName(C.name)
                from sys.tables T join sys.columns C on T.object_id=C.object_id and T.object_id=OBJECT_ID('UnPivotData','U') and C.Name like'U'+'[0-9]%'
                 FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')
    SET @TOT = STUFF((SELECT distinct ',' + QuoteName(C.name)
                from sys.tables T join sys.columns C on T.object_id=C.object_id and T.object_id=OBJECT_ID('UnPivotData','U') and C.Name like'T'+'[0-9]%'
                 FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)'),1,1,'')

    Declare @Query1 Nvarchar(MAX),@Query2 Nvarchar(MAX),@Query3 Nvarchar(MAX),@Query4 Nvarchar(MAX),@Query5 Nvarchar(MAX)

    Set @Query1='select ID,SNO  from
         (
         Select ID,'+@SNO+' from UnPivotData
         )L
         unpivot
         (
            SNo for col in('+ @SNO +')
         ) u'

    Set @Query2='select ID,PDT  from
         (
         Select ID,'+@PDT+' from UnPivotData
         )L
         unpivot
         (
            PDT for col in('+ @PDT +')
         ) u'

    Set @Query3='select ID,QTY  from
         (
         Select ID,'+@QTY+' from UnPivotData
         )L
         unpivot
         (
            QTY for col in('+ @QTY +')
         ) u'

    Set @Query4='select ID,UNIT  from
         (
         Select ID,'+@UNIT+' from UnPivotData
         )L
         unpivot
         (
            UNIT for col in('+ @UNIT +')
         ) u'

    Set @Query5='select ID, TOT  from
        (
        Select ID,'+@TOT+' from UnPivotData
        )L
        unpivot
        (
        TOT for col in('+ @TOT +')
        ) u'


    Declare @t1 table
    (
    id int,
    SNO Smallint
    )
    Declare @t2 table
    (
    id int,
    PDT Varchar(3)
    )
    Declare @t3 table
    (
    id int,
    QTY Smallint
    )
    Declare @t4 table
    (
    id int,
    UNIT Smallint
    )
    Declare @t5 table
    (
    id int,
    TOT Smallint
    )
    Insert into @T1 execute ( @Query1 )
    Insert into @T2 execute ( @Query2 )
    Insert into @T3 execute ( @Query3 )
    Insert into @T4 execute ( @Query4 )
    Insert into @T5 execute ( @Query5 )


    ;With Cte
    as
    (
    Select UD.Id,BILLNO,Cus_Name,[Date],Tot_Bal,SNO,Row_Number() over(partition by T1.ID Order by T1.ID)Row_NO--,PDT,QTY,UNIT,TOT
    ,Total,CusCode
    from UnPivotData UD join @t1 T1  on UD.Id=T1.id
    )
    ,
    Cte1
    as
    (
    Select Cte.*,PDT from Cte Join
    (Select *,Row_Number() over(partition by ID Order by ID)Row_NO from  @t2) T2 on Cte.ID=T2.ID and Cte.Row_NO=T2.Row_NO
    )
    ,
    Cte2
    as
    (
    Select Cte1.*,QTY from Cte1 Join
    (Select *,Row_Number() over(partition by ID Order by ID)Row_NO from  @t3) T3 on Cte1.ID=T3.ID and Cte1.Row_NO=T3.Row_NO
    )
    ,
    Cte3
    as
    (
    Select Cte2.*,UNIT from Cte2 Join
    (Select *,Row_Number() over(partition by ID Order by ID)Row_NO from  @t4) T4 on Cte2.ID=T4.ID and Cte2.Row_NO=T4.Row_NO
    )
    ,
    Cte4
    as
    (
    Select Cte3.*,TOT from Cte3 Join
    (Select *,Row_Number() over(partition by ID Order by ID)Row_NO from  @t5) T5 on Cte3.ID=T5.ID and Cte3.Row_NO=T5.Row_NO
    )
    Select Id,BILLNO,Cus_Name,[Date],Tot_Bal,SNO,PDT,QTY,UNIT,TOT
    ,Cuscode
     from Cte4
person JayaPrakash    schedule 02.06.2017

Вы можете развернуть его вручную:

select BILLNO, CUS_NAME, DATE, TOT_BAL, S1 as SNO, D1 as Pdt, Q1 as QTY, U1 as Unit, T1 as Tot, CUSCODE
from [tmpFormat]
union all
select BILLNO, CUS_NAME, DATE, TOT_BAL, S2, D2, Q2, U2, T2, CUSCODE
from [tmpFormat]
union all
select BILLNO, CUS_NAME, DATE, TOT_BAL, S3, D3, Q3, U3, T3, CUSCODE
from [tmpFormat]
person Marc Guillot    schedule 01.06.2017