2010-02-11 2 views
2

БД: SQL Server 2005Динамические столбцы - SQL Server - Месяцы как столбцы

У нас есть таблица, которая имеет данные таким образом:

Project    Year  Jan     Feb     Mar     Apr     May     Jun     Jul     Aug     Sep     Oct     Nov     Dec 
-------------------- ----------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 
11-11079    2008  0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     75244.90 
11-11079    2009  466.00    0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00 
11-11079    2010  855.00    0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00     0.00 
01-11052    2009  56131.00    0.00     36962.00    -61596.00    2428.00    84.00     0.00     0.00     0.00     0.00     0.00     0.00 

Кто-то хотел бы, чтобы данные, которые будут отображаться в виде одной строки для всего проекта. Столбцы будут динамически зависимы от того, сколько лет оно будет в будущем. Пример может быть:

Project  Jan-2009  Feb-2009  Mar-2009  Apr-2009... Dec-2009  Jan-2010 
-------------- ------------ ------------ ------------ ----------- ------------ --------- 
11-11079  466.00  0.00   0.00   0.00  0.00   855.00  
01-11052  56131.00  0.00   36962.00  -61596.00 2428.00  0.00 

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

Динамический SQL со сводной таблицей?
Или некоторые довольно широкомасштабные манипуляции с использованием SQL, temp-таблиц, объединений и объединений?
Любые мысли об использовании функции сводной таблицы SSIS?

+1

Пожалуйста, не используйте термин «MS SQL» в заголовке или в своем вопросе. Нет такого продукта. Использование этого затрудняет поиск поиском вашего вопроса и смешивает вещи между SQL Server и MySQL. –

+0

heh - Я проигнорировал вопросы tsql, на которые я знаю ответ, потому что я читаю MSSQL как MySQL –

+0

John - эти имена близки и запутанны, но справедливости ради людей, которые публикуют здесь, Microsoft SQL Server называется MSSQL в некотором роде. Посмотрите путь к двоичным файлам :-) C: \ Program Files \ Microsoft SQL Server \ MSSQL10.TEST2008 \ MSSQL Или PowerShell> Get-Service, который производит MSSQL $ TEST2008 как имя службы, для меня, по крайней мере. – onupdatecascade

ответ

4

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

Шаг 1: UNPIVOT

Вы можете использовать SQL 2005 UNPIVOT команду, или использовать CROSS JOIN технику. Вот примеры того и другого. Примечание. Я оставил месяцы посередине, чтобы все было просто. Просто добавьте их.

-- CROSS JOIN method (also works in SQL 2000) 
SELECT 
    P.Project, 
    Mo = 
     DateAdd(mm, 
     X.MonthNum, 
     DateAdd(yy, P.[Year] - 1900, '19000101') 
    ), 
    Amount = 
     CASE X.MonthNum 
     WHEN 0 THEN Jan 
     WHEN 1 THEN Feb 
     WHEN 11 THEN Dec 
     END 
FROM 
    ProjectData P 
    CROSS JOIN (
     SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 11 
    ) X (MonthNum) 

Каждая строка повторяется 12 раз, то сазе вытаскивает только один месяц для каждой строки, в результате чего данные хорошо unpivoted.

-- UNPIVOT method 
SELECT 
    P.Project, 
    Mo = 
     DateAdd(mm, 
      Convert(int, P.MonthNum), 
      DateAdd(yy, P.[Year] - 1900, '19000101') 
     ), 
    P.Amount 
FROM 
    (
     SELECT Project, [Year], [0] = Jan, [1] = Feb, [11] = Dec 
     FROM ProjectData 
    ) X UNPIVOT (Amount FOR MonthNum IN ([0], [1], [11])) P 

DROP TABLE ProjectData 

Ни один из этих методов не является очевидным победителем. Иногда один работает лучше, чем другой (в зависимости от поворота данных). Метод UNPIVOT использует фильтр в плане выполнения, который CROSS JOIN не делает.

Шаг 2: Pivot Опять

Теперь, как использовать unpivoted данные.Вы не сказали, как ваш кто-то будет потреблять это, но так как вам нужно будет поместить данные в выходной файл какого-либо рода, я предлагаю использовать SSRS (Sql Server Reporting Services), который поставляется с SQL Server 2005 за дополнительную плату.

Просто используйте объект отчета Matrix для поворота одного из запросов выше. Этот объект с радостью определяет значения данных для создания меток столбцов во время выполнения отчета и звучит точно так, как вам нужно. Если вы добавите столбец, который форматирует дату точно так, как вам нравится, вы можете заказать столбец Mo, но используйте новое выражение как метку столбца.

SSRS также имеет широкий спектр форматов и доступных вариантов планирования. Например, вы можете отправить электронное письмо в файл Excel или сохранить веб-страницу в общем доступе к файлу.

Пожалуйста, дайте мне знать, если я что-то оставил.

Для тех, кто хотел бы видеть код, указанный выше в действии, вот некоторые создания сценария для вас:

USE tempdb 

CREATE TABLE ProjectData (
    Project varchar(10), 
    [Year] int, 
    Jan decimal(15, 2), 
    Feb decimal(15, 2), 
    Dec decimal(15, 2) 
) 

SET NOCOUNT ON 

INSERT ProjectData VALUES ('11-11079', 2008, 0.0, 0.0, 75244.90) 
INSERT ProjectData VALUES ('11-11079', 2009, 466.0, 0.0, 0.0) 
INSERT ProjectData VALUES ('11-11079', 2010, 855.0, 0.0, 0.0) 
INSERT ProjectData VALUES ('01-11052', 2009, 56131.0, 0.0, 0.0) 
+0

после отправки моего оригинального вопроса, я провел день, глядя на данные, и он выскочил на меня, что данные уже повернуты. В тот момент, когда я побежал на нем быстро, свет продолжался, и я смог построить его так, как хотел. Итак, ваша техника - это то, как я закончил! – ichauvin

-1

Я думаю, вы могли бы сделать это с вложенным циклом while и некоторым динамическим SQL. Это было бы медленным решением, если вы не сможете сохранить финальную таблицу или если вам нужно каждые полгода обновлять все столбцы. Однако, если он просто аддитивен, это может быть не плохо. В любом случае, так я бы это сделал:

  1. Out loop выбирает самый старый год.
  2. Внутренний цикл выбирает первый месяц.
  3. Внутри внутреннего цикла - добавьте столбец с именем - в таблицу.
  4. Внутри Внутренний контур - таблица обновления со всей информации для новых - колонок с динамическим SQL
  5. перебирать внутренний контур для каждого месяца
  6. перебирать внешний контур для каждого года.
+0

-1. Извините, RandomBen, но цикл просто не поддерживается вообще, когда четкие и простые решения на основе набора доступны для разворачивания, а затем снова поворачиваются. Производительность с петлями будет абсолютно ужасной. – ErikE

0

Я написал ХП с именем pivot_query, которые могут помочь с этим, источник here , примеры с необработанными данными here.

With your data: 

create table ProjectData 
    (
    Project      varchar(20), 
    [Year]      Integer, 
    Jan       decimal(12,2), 
    Feb       decimal(12,2), 
    Mar       decimal(12,2), 
    Apr       decimal(12,2), 
    May       decimal(12,2), 
    Jun       decimal(12,2), 
    Jul       decimal(12,2), 
    Aug       decimal(12,2), 
    Sep       decimal(12,2), 
    Oct       decimal(12,2), 
    Nov       decimal(12,2), 
    Dec       decimal(12,2) 
    ); 

insert into ProjectData values ('11-11079',2008, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 75244.90); 
insert into ProjectData values ('11-11079',2009, 466.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00); 
insert into ProjectData values ('11-11079',2010, 855.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00) ; 
insert into ProjectData values ('01-11052',2009, 56131.00, 0.00, 36962.00, -61596.00, 2428.00, 84.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00); 

declare @mySQL varchar(MAX) 

set @mySQL = 'select * from ProjectData' 

exec pivot_query @mySQL, 'Project', 'Year', 'max(Jan) Jan,max(Feb) Feb,max(Mar) Mar,max(Apr) Apr,max(Jun) Jun,max(Jul) Jul,max(Aug) Aug,max(Sep) Sep,max(Oct) Oct,max(Nov) Nov,max(Dec) Dec' 

Results: 
Project    2008_Jan  2008_Feb  2008_Mar  2008_Apr  2008_Jun  2008_Jul  2008_Aug  2008_Sep  2008_Oct  2008_Nov  2008_Dec  2009_Jan  2009_Feb  2009_Mar  2009_Apr  2009_Jun  2009_Jul  2009_Aug  2009_Sep  2009_Oct  2009_Nov  2009_Dec  2010_Jan  2010_Feb  2010_Mar  2010_Apr  2010_Jun  2010_Jul  2010_Aug  2010_Sep  2010_Oct  2010_Nov  2010_Dec 
-------------------- ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ 
01-11052    NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   56131.00  .00   36962.00  -61596.00 84.00  .00   .00   .00   .00   .00   .00   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL   NULL 
11-11079    .00   .00   .00   .00   .00   .00   .00   .00   .00   .00   75244.90  466.00  .00   .00   .00   .00   .00   .00   .00   .00   .00   .00   855.00  .00   .00   .00   .00   .00   .00   .00   .00   .00   .00 

Не точное но чертовски близко. :-)

+0

Я забыл добавить месяц мая, но SO не позволит мне редактировать сообщение, чтобы положить его. :-) –

+0

Святая крада, Рон. Зачем вам когда-либо использовать этот огромный процессорный код, когда проблема может быть решена с помощью набора кода и существующих инструментов SQL Server? – ErikE

+0

Он является общим и работает для любого запроса без необходимости знать значения ваших столбцов. Сэкономил нам метрические тонны времени разработки во многих отчетах о стиле «поворота». Я не писал это только для этого. :-) –