Данные сводной таблицы в табличном формате, первый столбец должен быть именем столбца, а остальные должны быть значением

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

Простой оператор выбора выглядит следующим образом

SELECT  product_Id,product_Name,product_Price ,product_Description,product_weight  
from tblProduct
WHERE  product_Id in (1139,1140,1144)

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

введите здесь описание изображения

Я знаю, что мне нужно использовать поворот, чтобы получить желаемый результат. и я пробовал следующим образом

SELECT MAX(ISNULL([1139],'')),MAX(ISNULL([1140],'')),MAX(ISNULL([1144],'')) 
FROM
(
  SELECT product_Id,product_Name,product_Price,product_Description,product_weight 
  FROM tblProduct where product_Id in (1139,1140,1144)
)s 
PIVOT
(
  MAX(product_Name)
  FOR product_Id in ([1139],[1140],[1144])
) AS PVT

но это делается только для одного столбца, но мне нужно для всех атрибутов.


person rahularyansharma    schedule 28.03.2013    source источник


Ответы (1)


Поскольку вы пытаетесь агрегировать атрибуты, которые существуют в нескольких столбцах, это указывает на то, что вам необходимо применить как UNPIVOT и PIVOT.

UNPIVOT возьмет значения ваших столбцов и преобразует их в строки. Код для разворота будет похож на этот:

select product_id, header, value
from
(
  select product_id, 
    product_name, 
    cast(product_price as varchar(10)) product_price, 
    product_weight
  from tblProduct
) p
unpivot
(
  value
  for header in (product_name, product_price, product_weight)
) unp

См. SQL Fiddle с демонстрацией. Вы заметите, что здесь есть подзапрос, который преобразует столбец product_price в varchar. Это связано с тем, что типы данных столбцов, которые вы хотите использовать в строках, должны быть одинаковыми. Поэтому вам, возможно, придется выполнить преобразование данных, чтобы заставить это работать правильно.

Unpivot генерирует результат, который выглядит следующим образом:

| PRODUCT_ID |         HEADER | VALUE |
---------------------------------------
|        141 |   product_name |  A141 |
|        141 |  product_price |   200 |
|        141 | product_weight | 200gm |

Как только данные находятся в строках, вы можете применить функцию PIVOT к значениям столбца product_id.

select header, [141], [142], [143], [144]
from
(
  select product_id, header, value
  from
  (
    select product_id, 
      product_name, 
      cast(product_price as varchar(10)) product_price, 
      product_weight
    from tblProduct
  ) p
  unpivot
  (
    value
    for header in (product_name, product_price, product_weight)
  ) unp
) d
pivot
(
  max(value)
  for product_id in ([141], [142], [143], [144])
) piv

См. SQL Fiddle с демонстрацией. Это дает результат:

|         HEADER |   141 |   142 |   143 |   144 |
--------------------------------------------------
|   product_name |  A141 |  A142 |  A143 |  A144 |
|  product_price |   200 |   300 |  4000 |  5000 |
| product_weight | 200gm | 300gm | 400gm | 100gm |

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

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(product_id) 
                    from tblProduct
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT header, ' + @cols + ' 
              from 
             (
                select product_id, header, value
                from
                (
                  select product_id, 
                    product_name, 
                    cast(product_price as varchar(10)) product_price, 
                    product_weight
                  from tblProduct
                ) p
                unpivot
                (
                  value
                  for header in (product_name, product_price, product_weight)
                ) unp
            ) x
            pivot 
            (
                max(value)
                for product_id in (' + @cols + ')
            ) p '

execute(@query)

См. SQL Fiddle с демонстрацией. Это приведет к тому же результату, что и статическая/жестко закодированная версия запроса.

person Taryn    schedule 28.03.2013
comment
@rahularyansharma Спасибо, я добавил динамическую версию кода на случай, если у вас будет неизвестное количество product_id для преобразования в столбцы. - person Taryn; 28.03.2013
comment
вы делаете меня своим фанатом для основных вопросов :) - person rahularyansharma; 28.03.2013
comment
на самом деле я уже передаю productIds через запятую в хранимой процедуре @ProductIds nvarchar(500) - person rahularyansharma; 28.03.2013
comment
Количество элементов в списке выбора превышает максимально допустимое число в 4096 элементов. - person rahularyansharma; 28.03.2013
comment
Я не хочу запускать этот запрос для всех столбцов, а не только для идентификаторов продуктов, которые я передал в переменной @ProductIds ... это может быть максимум 4 - person rahularyansharma; 28.03.2013
comment
@rahularyansharma Если у вас максимум 4 элемента, то любое из этих решений будет работать. :) - person Taryn; 28.03.2013
comment
теперь я столкнулся с проблемой с именем столбца этих 4 столбцов, поскольку они меняются каждый раз, поскольку имя первого столбца является заголовком, я хочу продолжить с остальными именами столбцов, такими как Product1, Product2, Product3 и Product4.. от макс до макс может быть 4 продукта но минимум продуктов может быть ноль.. но для меня это нормально, если они возвращают null для столбцов, которые не имеют значений - person rahularyansharma; 28.03.2013
comment
@rahularyansharma Я не уверен, что понимаю. Можете ли вы опубликовать новый вопрос? - person Taryn; 28.03.2013
comment
@rahularyansharma отлично, киньте ссылку здесь в комментариях, я посмотрю - person Taryn; 28.03.2013