2015-10-12 2 views
1

Я получил упорядоченную таблицу Microsoft Сервера следующей формы:Преобразовать таблицу из строк в столбцы

Name Product 
    ------------------ 
1 | Mayer Product_1 
2 | Mayer Product_1 
3 | Mayer Product_2 

И я хотел бы получить следующий результат:

Name Purchase_1 Purchase_2 Purchase_3 
    ----------------------------------------- 
1 | Mayer Product_1 Product_1 Product_2 

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

+0

- это имя и продукт только 2 столбца в исходной таблице? – JamieD77

+0

@ JamieD77 Да, только эти два. :) – JimBoy

+0

, тогда преобразование их в столбцы не имеет смысла, потому что нет определенного порядка. – JamieD77

ответ

3

Dynamic PIVOT ваш друг:

LiveDEMO

CREATE TABLE #mytable(
    Name VARCHAR(80) NOT NULL 
    ,Product VARCHAR(160) NOT NULL 
); 
INSERT INTO #mytable VALUES ('Mayer','Product_1'); 
INSERT INTO #mytable VALUES ('Mayer','Product_1'); 
INSERT INTO #mytable VALUES ('Mayer','Product_2'); 
INSERT INTO #mytable VALUES ('Kowalsky','Product_1'); 
INSERT INTO #mytable VALUES ('Kowalsky','Product_2'); 
INSERT INTO #mytable VALUES ('Kowalsky','Product_3'); 
INSERT INTO #mytable VALUES ('Kowalsky','Product_4'); 

DECLARE @cols NVARCHAR(MAX), 
     @cols_piv NVARCHAR(MAX), 
     @query NVARCHAR(MAX) 
     ,@max INT = 0; 

SELECT @max = MAX(c) 
FROM (
    SELECT Name, COUNT(Product) AS c 
    FROM #mytable 
    GROUP BY Name) AS s; 

SET @cols = STUFF(  
      (SELECT ',' + CONCAT('[',c.n, '] AS Purchase_',c.n, ' ') 
      FROM (SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n) 
      WHERE c.n <= @max 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,''); 

SET @cols_piv = STUFF(
      (SELECT ',' + CONCAT('[',c.n, '] ') 
      FROM (SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n) 
      WHERE c.n <= @max 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'');   

SET @query = N'SELECT Name, ' + @cols + ' from 
      (
       select Name, Product, 
       [rn] = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Product) 
       from #mytable 
      ) x 
      pivot 
      (
       max(Product) 
       for rn in (' + @cols_piv + ') 
      ) p '; 

-- SELECT @query; 

EXEC [dbo].[sp_executesql] 
    @query; 

Это может быть сложным на первый, но это действительно просто. Нормальный PIVOT требует, чтобы вы знали список столбцов заранее. Это не вариант в вашем случае, поэтому вам нужно создать столбец и использовать Dynamic-SQL.

Как это работает:

  1. @max содержит максимальное количество столбцов в строке
  2. @cols содержит SELECT список столбцов с псевдонимами
  3. @cols_piv содержит список номеров [1], [2], ... @max
  4. сцепить его с нормальным PIVOT запроса
  5. Выполните его и получите удовольствие от ваших результатов.

Предупреждение:

  • Я использовал sys.objects как мой генератор чисел. Вы можете заменить его тем, что хотите (рекурсивная CTE/многоступенчатая CTE/таблица таблеток ...).

  • Если вы используете SQL Server 2008, вам необходимо заменить CONCAT на +.

+0

спасибо, lad2025! Это было очень быстро! :) Поскольку я новичок в SQL, я не очень понимаю код, который вы предоставили. Есть ли более простой способ сделать это? Или вы могли бы объяснить мне, что вы делаете в коде выше? – JimBoy

+0

Спасибо за ваше объяснение! :) К сожалению, я не вижу, где мне нужно поместить имена объектов, например [db_name]. [Dbo]. [Table_name] и [column_name]. Можете ли вы дать мне несколько указателей здесь? Еще раз спасибо! – JimBoy

+0

@Jimboy Замените #mytable вашим столом;) – lad2025