Запрос, преобразующий определенные строки в имена столбцов

StackOverflow https://stackoverflow.com/questions/926209

Вопрос

У меня есть пара таблиц, которые выглядят следующим образом Таблица 1

user_id   |  name
-------------------------   
x111      |   Smith, James
x112      |   Smith, Jane

и т.д..

Таблица 2

id    |   code    |    date       |  incident_code    | user_id
-----------------------------------------------------------------
1     |    102008 |   10/20/2008  |    1              | x111
2     |    113008 |   11/30/2008  |    3              | x111
3     |    102008 |   10/20/2008  |    2              | x112
4     |    113008 |   11/30/2008  |    5              | x112 

То, что я хотел бы показать, это что-то вроде этого

user_id     |    user_name    |   INCIDENT IN OCT 2008   | INCIDENT IN NOV 2008
------------------------------------------------------------------------------ 
x111        |    Smith, John  |   1                      | 3
x112        |    Smith, Jane  |   2                      | 5

и т.д..

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

Некоторые заголовки столбцов были бы статическими, в то время как другие создавались бы на основе даты.Кто-нибудь знает, как я могу это сделать, используя sql server 2005?Некоторые примеры были бы очень полезны.

Заранее благодарю

Это было полезно?

Решение

Вот решение, которое генерирует и запускает динамический SQL с помощью PIVOT:

DECLARE @pivot_list AS VARCHAR(MAX)

--
;
WITH    cols
          AS ( SELECT DISTINCT
                        'INCIDENT IN ' + LEFT(UPPER(CONVERT(VARCHAR, [date], 107)),
                                              3) + ' '
                        + SUBSTRING(UPPER(CONVERT(VARCHAR, [date], 107)), 9, 4) AS col
               FROM     so926209_2
             )
    SELECT  @pivot_list = COALESCE(@pivot_list + ', ', '') + '[' + col + ']'
    FROM    cols

--
DECLARE @template AS VARCHAR(MAX)
SET @template = 'WITH incidents AS (
SELECT  [user_id],
        incident_code,
        ''INCIDENT IN '' + LEFT(UPPER(CONVERT(VARCHAR, [date], 107)), 3)
        + '' '' + SUBSTRING(UPPER(CONVERT(VARCHAR, [date], 107)), 9, 4) AS col
FROM    so926209_2
)
,results AS (
SELECT * FROM incidents PIVOT (MAX(incident_code) FOR col IN ({@pivot_list})) AS pvt
)
SELECT results.[user_id]
    ,so926209_1.[name]
    ,{@select_list}
FROM results INNER JOIN so926209_1 ON so926209_1.[user_id] = results.[user_id]
'

DECLARE @sql AS VARCHAR(MAX)
SET @sql = REPLACE(REPLACE(@template, '{@pivot_list}', @pivot_list), '{@select_list}', @pivot_list)

--PRINT @sql
EXEC (@sql)

Где so926209_1, so926209_2 являются ли ваши таблица 1 и таблица 2

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

Другие советы

Вы хотите повернуть http://msdn.microsoft.com/en-us/library/ms177410.aspx

Это звучит как задача составления отчета.Отчетность, которую с точки зрения базы данных часто называют OLAP, оперативной аналитической обработкой, как правило, довольно часто отличается от "традиционного" доступа к базе данных, OLTP (оперативной обработки транзакций), тем, что она довольно часто состоит из больших совокупностей данных, охватывающих более длительные периоды времени.Довольно часто это тот тип агрегации, который вы ищете.

Использование Pivot, как предложил Tetraneutron, будет достаточным для небольших наборов данных.Однако по мере роста объема данных, по которым вам нужно составлять отчет, вам может понадобиться что-то более продвинутое.OLAP предоставляется службами SQL Server Analysis Services (SSAS), доступными в 2005 и 2008 годах.Используя SSAS, вы можете создавать многомерные хранилища данных, которые предварительно агрегируют данные либо непосредственно из базы данных OLTP, либо из базы данных промежуточного хранилища данных.Многомерные данные (обычно называемые кубами) предоставляют гораздо более быстрый способ доступа к данным того типа, который вы можете получить из сводной таблицы, без ущерба для производительности стандартной обработки транзакций в вашей базе данных OLTP.

Если у вас есть более чем небольшой объем данных, по которым вам нужно составить отчет, я рекомендую вам ознакомиться с SQL Server Analysis Services 2005, OLAP, Cubes и MDX (многомерные расширения для T-SQL). Настройка OLAP-куба требует большего обучения, но после его настройки преимущества его наличия могут быть огромными, если у вас есть значительные потребности в отчетности.

Подобный запрос сработал бы:

select
    u.User_id,
    u.Name,
    Okt2008Sum = sum(case when i.date between 
        '2008-10-01' and '2008-11-01' then 1 else 0 end),
    Nov2008Sum = sum(case when i.date between 
        '2008-11-01' and '2008-12-01'then 1 else 0 end)
from #incidents i
inner join #users u on i.user_id = u.user_id
group by u.user_id, u.name

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

create table #months (
    MonthName varchar(25),
    StartDate datetime
)

insert into #months values ('Okt2008','2008-10-01')
insert into #months values ('Nov2008','2008-11-01')

declare @query varchar(8000)
select @query = 'select u.User_id, u.Name '

select @query = @query + ', ' + MonthName + 
    ' = sum(case when i.date between ''' + cast(StartDate as varchar) + 
    ''' and ''' + cast(dateadd(m,1,StartDate) as varchar) + 
    ''' then 1 else 0 end) '
from #Months

select @query = @query + '
    from #incidents i
    inner join #users u on i.user_id = u.user_id
    group by u.user_id, u.name'

exec (@query)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top