Как повернуть несколько столбцов без агрегации - PullRequest
0 голосов
/ 25 мая 2018

Я использую SqlServer, и я должен признать, что я не очень хорошо с ним ... Это может быть и простой вопрос для опытных пользователей (я надеюсь)

У меня есть две таблицы, которые выглядят какthis

Первая таблица (ID не является первичным ключом)

ID      IdCust   Ref
1       300      123
1       300      124
2       302      345

И вторая (ID не является первичным ключом)

ID     Ref      Code    Price
1      123      A       10
1      123      Y       15
2      124      A       14
3      345      C       18

Вво второй таблице столбец «Ref» является внешним ключом «Ref» в первой таблице

Я пытаюсь получить следующий вывод:

The result what i want

[РЕДАКТИРОВАТЬ] Столбцы "Акции", "Код" и "Цена" могут иметь значения х, поэтому я заранее не знаю ...

Я пробовал так много вещей, как "PIVOT"но это не дало мне правильный результат, поэтому я надеюсь, что кто-то может решить мою проблему ...

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

@ YogeshSharma предоставил отличный ответ.

То же самое сделано с использованием Pivot; SQL Fiddle Demo .

Функционально нет разницы между двумя ответами.Однако решение Йогеша проще для понимания и работает лучше;так что лично я бы выбрал это ... Я включил этот ответ только потому, что вы упомянули PIVOT в вопросе:

select ft.Id
, ft.IdCust
, ft.Ref
, x.Stock1
, x.Code1
, x.Price1
, x.Stock2
, x.Code2
, x.Price2
from FirstTable ft
left outer join (
  select Ref
  , max([Stock1]) Stock1
  , max([Stock2]) Stock2
  , max([Code1]) Code1
  , max([Code2]) Code2
  , max([Price1]) Price1
  , max([Price2]) Price2
  from
  (
    select Ref
    , Id Stock
    , Code
    , Price
    , ('Stock' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) StockLineNo
    , ('Code' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) CodeLineNo
    , ('Price' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) PriceLineNo
    from SecondTable
  ) st
  pivot (max(Stock) for StockLineNo in ([Stock1],[Stock2])) pvtStock
  pivot (max(Code) for CodeLineNo in ([Code1],[Code2])) pvtCode
  pivot (max(Price) for PriceLineNo in ([Price1],[Price2])) pvtPrice
  Group by Ref
) x
on x.Ref = ft.Ref
order by ft.Ref

Как и решение Йогеша, оно будет обрабатывать столько столбцов, сколько вы укажете;он не будет динамически изменять количество столбцов в соответствии с данными.Для этого вам нужно сделать динамический SQL.Тем не мение;если вам нужно сделать это, более вероятно, что вы пытаетесь решить проблему неправильно ... так что подумайте над своим дизайном / определите, действительно ли вам нужны дополнительные столбцы для результата, а не дополнительные строки / какой-то альтернативный подход ...


Вот реализация Dynamic SQL, основанная на ответе @ YogeshSharma: DBFiddle

declare @sql nvarchar(max) = 'select id, IdCust, Ref'
select @sql = @sql + '
        ,max(case when Seq = 1 then stock end) as [Stock' + rowNumVarchar + '] 
        ,max(case when Seq = 1 then code end) as [Code' + rowNumVarchar + ']
        ,max(case when Seq = 1 then price end) as [Price' + rowNumVarchar + ']
'
from 
(
    select distinct cast(row_number() over (partition by ref order by ref) as nvarchar) rowNumVarchar
    from second s
) z
set @sql = @sql + '
    from (select f.*, s.Id Stock, s.Code, s.Price,
                 row_number() over (partition by f.Ref order by s.id) as Seq
         from first f
         inner join second s on s.Ref = f.Ref 
         ) t
    group by id, IdCust, Ref;
'
print @sql --see what the SQL produced is
exec (@sql)

(Вот ссылка SQL Fiddle для этогоодин, но он не работает, несмотря на то, что SQL действителен

0 голосов
/ 25 мая 2018

Используйте функцию row_number() и выполните условное агрегирование:

select id, IdCust, Ref,
       max(case when Seq = 1 then stock end) as [Stock A], -- second table *id*
       max(case when Seq = 1 then code end) as [Code 1],
       max(case when Seq = 1 then price end) as [Price1],
       max(case when Seq = 2 then stock end) as [Stock B], -- second table *id*
       max(case when Seq = 2 then code end) as [Code 2],
       max(case when Seq = 2 then price end) as [Price2]
from (select f.*, s.Id Stock, s.Code, s.Price,
             row_number() over (partition by f.Ref order by s.id) as Seq
     from first f
     inner join second s on s.Ref = f.Ref 
     ) t
group by id, IdCust, Ref;

Однако это будет соответствовать известным значениям ещедля этого вам понадобится решение dynamic .

...