2014-10-01 4 views
2

Я получил столSQL Pivot с динамическими генерируемыми столбцами и агрегатной функции

CREATE TABLE [dbo].[newTable](
    [EBELN] [nvarchar](20) NOT NULL, 
    [EBELP] [nvarchar](10) NOT NULL, 
    [VGABE] [nvarchar](2) NOT NULL, 
    [MENGE] [numeric](15, 3) NULL, 
    [DMBTR] [numeric](15, 2) NULL 

) 

Он имеет эти записи

insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0001', '1', 1 , 27.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0001', '2', 1 , 27.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0002', '1', 1 , 10.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0002', '2', 1 , 10.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0001', '1', 1 , 22.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0001', '2', 1 , 22.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0002', '1', 1 , 32.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0002', '2', 1 , 32.95) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '1', 1 , 400.00) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '1', 1 , 400.00) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '2', 1 , 400.00) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0002', '1', 1 , 200.00) 
Go 
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0002', '2', 1 , 200.00) 
Go 

Thats ВЫБОР *

EBELN    EBELP  VGABE MENGE         DMBTR 
-------------------- ---------- ----- -------------- --------------------------------------- 
3000000004   0001  1  1.000         27.95 
3000000004   0001  2  1.000         27.95 
3000000004   0002  1  1.000         10.95 
3000000004   0002  2  1.000         10.95 
3000000010   0001  1  1.000         22.95 
3000000010   0001  2  1.000         22.95 
3000000010   0002  1  1.000         32.95 
3000000010   0002  2  1.000         32.95 
4151516119   0001  1  1.000         400.00 
4151516119   0001  1  1.000         400.00 
4151516119   0001  2  1.000         400.00 
4151516119   0002  1  1.000         200.00 
4151516119   0002  2  1.000         200.00 
3000000004   0001  2  1.000         27.95 
3000000004   0002  1  1.000         10.95 
3000000004   0002  2  1.000         10.95 
3000000010   0001  1  1.000         22.95 
3000000010   0001  2  1.000         22.95 
3000000010   0002  1  1.000         32.95 
3000000010   0002  2  1.000         32.95 
4151516119   0001  1  1.000         400.00 
4151516119   0001  1  1.000         400.00 
4151516119   0001  2  1.000         400.00 
4151516119   0002  1  1.000         200.00 
4151516119   0002  2  1.000         200.00 
4151516177   0002  6  1.000         111.00 
4151516177   0002  8  1.000         111.00 

Что мне нужно и требуется динамический стержень, который генерирует этот результат.

+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ 
| EBELN | EBELP | c_DMBTR_1 | c_MENGE_1 | c_DMBTR_2 | c_MENGE_2 | c_DMBTR_6 | c_MENGE_6 | c_DMBTR_8 | c_MENGE_8 | 
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ 
| 3000000004 | 0001 | 27.95  | 1   | 27.95  | 1   | NULL  | NULL  | NULL  | NULL  | 
| 3000000004 | 0002 | 10.95  | 1   | 10.95  | 1   | NULL  | NULL  | NULL  | NULL  | 
| [...]  |  |   |   |   |   |   |   |   |   | 
| 4151516119 | 0001 | 800.00 | 1   | 400.00 | 1   | NULL  | NULL  | NULL  | NULL  | 
| 4151516177 | 0002 | NULL  | NULL  | NULL  | NULL  | 111.00 | 1   | 111.00 | 1   | 
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ 

Я попробовал несколько решений, но ни один из них не получил результат, который я хочу получить.

Что мне нужно, это значение в VGABE которые (1,2,6,7,8,9,P,R) быть сцеплены для строковых имен c_DMBTR и c_MENGE. Но возможно, что, например, P или 7 не используется, поэтому я не хочу, чтобы для этого были столбцы. Я думаю, что сделать его динамичным - единственный возможный способ сделать это.

Значение от VGABE должно быть добавлено к имени столбца, как 'c_MENGE_'+VGABE и оно должно быть в порядке, а это значит, он должен начать с наименьшим значением из VGABE со всех столбцов, а затем следующее значение до каждого используемого значения от vgabe.

Если для одной позиции (EBELP) больше, чем одно значение из VGABE, как два раза 1 для POS 0001, как вы можете видеть EBELN 4151516119 я должен SUM (DMBTR) для этой позиции и VGABE Value. То же самое я должен делать с MENGE.

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

+0

Im using SQL Server 2014 и MS SQL Management Studio 2014 – JollyPopper

ответ

2

Для того, чтобы получить конечный результат, который вы хотите, вы сначала должны unpivot в DMBTR и MENGE столбцы, а затем применить функцию PIVOT для преобразования строки в столбцы.

Вы не указали, какую версию SQL Server вы используете. Я собираюсь угадать SQL Server 2005+. Начиная с SQL Server 2005, функция PIVOT была доступна, но для UNPIVOT вы также можете использовать CROSS APPLY, что, я думаю, было бы проще здесь.

Перед тем, как погрузиться в динамическую SQL-версию, я всегда хотел бы написать статическую версию, чтобы получить правильную логику, а затем преобразовать ее в динамический SQL. Первый шаг должен был бы преобразовать DMBTR и MENGE столбцы в строки:

select 
    t.ebeln, 
    t.ebelp, 
    new_col = c.orig_col + '_' + vgabe, 
    c.value 
from dbo.newTable t 
cross apply 
(
    select 'c_MENGE', menge union all 
    select 'c_DMBTR', dmbtr 
) c (orig_col, value); 

См SQL Fiddle with Demo. Это преобразует данные в:

|  EBELN | EBELP | NEW_COL | VALUE | 
|------------|-------|-----------|-------| 
| 3000000004 | 0001 | c_MENGE_1 |  1 | 
| 3000000004 | 0001 | c_DMBTR_1 | 27.95 | 
| 3000000004 | 0001 | c_MENGE_2 |  1 | 
| 3000000004 | 0001 | c_DMBTR_2 | 27.95 | 
| 3000000004 | 0002 | c_MENGE_1 |  1 | 
| 3000000004 | 0002 | c_DMBTR_1 | 10.95 | 

Как вы можете видеть, теперь у вас есть несколько строк, наряду с new_col с каскадными значениями c_MENGE_1, и т.д., которые будут ваши конечные столбцы.

После того как вы этот результат, можно применить функцию PIVOT:

select ebeln, 
    ebelp, 
    c_DMBTR_1, c_MENGE_1, c_DMBTR_2, c_MENGE_2, 
    c_DMBTR_6, c_MENGE_6, c_DMBTR_8, c_MENGE_8 
from 
(
    select 
    t.ebeln, 
    t.ebelp, 
    new_col = c.orig_col + '_' + vgabe, 
    c.value 
    from dbo.newTable t 
    cross apply 
    (
    select 'c_MENGE', menge union all 
    select 'c_DMBTR', dmbtr 
) c (orig_col, value) 
) d 
pivot 
(
    sum(value) 
    for new_col in (c_DMBTR_1, c_MENGE_1, c_DMBTR_2, c_MENGE_2, 
        c_DMBTR_6, c_MENGE_6, c_DMBTR_8, c_MENGE_8) 
) piv 
order by ebeln, ebelp; 

См SQL Fiddle with Demo.

Теперь, когда у вас есть правильная логика, вы захотите преобразовать ее в динамический SQL. Это начнется с создания строки sql из ваших новых имен столбцов. Для этого, вы будете использовать FOR XML PATH:

select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + vgabe) 
        from dbo.NewTable t 
        cross apply 
        (
         select 'c_DMBTR', 1 union all 
         select 'c_MENGE', 2 
        ) c (col, so) 
        group by col, so, vgabe 
        order by vgabe, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

Это похоже на код, который я использовал в статической версии. Он получает список значений vgabe и объединяет его с именем 2 столбцов, которые вы хотите PIVOT (, MENGE). Я также предоставляю порядок сортировки для этих столбцов, поэтому вы можете заказать их, как вам нужно. Полный динамический код SQL будет:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + vgabe) 
        from dbo.NewTable t 
        cross apply 
        (
         select 'c_DMBTR', 1 union all 
         select 'c_MENGE', 2 
        ) c (col, so) 
        group by col, so, vgabe 
        order by vgabe, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query 
    = 'SELECT ebeln, ebelp,' + @cols + N' 
    from 
    (
     select 
     t.ebeln, 
     t.ebelp, 
     new_col = c.orig_col + ''_'' + vgabe, 
     c.value 
     from dbo.newTable t 
     cross apply 
     (
     select ''c_MENGE'', menge union all 
     select ''c_DMBTR'', dmbtr 
    ) c (orig_col, value) 
    ) x 
    pivot 
    (
     sum(value) 
     for new_col in (' + @cols + N') 
    ) p 
    order by ebeln, ebelp' 

exec sp_executesql @query; 

См. SQL Fiddle with Demo. Это дает результат:

|  EBELN | EBELP | C_DMBTR_1 | C_MENGE_1 | C_DMBTR_2 | C_MENGE_2 | C_DMBTR_6 | C_MENGE_6 | C_DMBTR_8 | C_MENGE_8 | 
|------------|-------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------| 
| 3000000004 | 0001 |  27.95 |   1 |  27.95 |   1 | (null) | (null) | (null) | (null) | 
| 3000000004 | 0002 |  10.95 |   1 |  10.95 |   1 | (null) | (null) | (null) | (null) | 
| 3000000010 | 0001 |  22.95 |   1 |  22.95 |   1 | (null) | (null) | (null) | (null) | 
| 3000000010 | 0002 |  32.95 |   1 |  32.95 |   1 | (null) | (null) | (null) | (null) | 
| 4151516119 | 0001 |  800 |   2 |  400 |   1 | (null) | (null) | (null) | (null) | 
| 4151516119 | 0002 |  200 |   1 |  200 |   1 |  111 |   1 |  111 |   1 | 
+0

Эй, там! Большое вам спасибо за ваш быстрый и подробный ответ! Специально для демонстрации логики в статическом и динамическом смысле! Великолепно. Я использую SQL Server 2014 и Management Studio 2014. Могу ли я задать вам другой вопрос? – JollyPopper

+0

Конечно, в чем вопрос? – Taryn

+0

1) Где мне нужно вставить LEFT JOIN с dbo.newTableHeader в качестве моей основной таблицы с EBELN, EBELP как PK на dbo.newTable. 2) Возможно ли расширить запрос. Я хочу добавить столбец c_COUNT_X, где X обозначает каждое значение VGABE. Он рассчитывает VGABE для каждого EBELP. Возможно, я смогу сделать CTE для подготовки стола для моих нужд и использовать его для соединения – JollyPopper

Смежные вопросы