Consulta transposição de determinadas linhas em nomes de coluna
-
06-09-2019 - |
Pergunta
Eu tenho um par de tabelas que esta aparência Tabela 1
user_id | name
-------------------------
x111 | Smith, James
x112 | Smith, Jane
etc ..
A Tabela 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
O que eu gostaria de exibição é algo como isto
user_id | user_name | INCIDENT IN OCT 2008 | INCIDENT IN NOV 2008
------------------------------------------------------------------------------
x111 | Smith, John | 1 | 3
x112 | Smith, Jane | 2 | 5
etc ..
O incident_code seria substituída pela descrição real do incidente que está localizado em outra mesa, mas eu pensei que eu iria ver como isso iria funcionar em primeiro lugar.
Alguns dos cabeçalhos das colunas seria estática, enquanto outros seriam criados com base na data. Alguém um sabe como eu posso fazer isso usando o sql server 2005? Alguns exemplos seria muito útil.
Agradecemos antecipadamente
Solução
Aqui está uma solução que gera e executa o SQL dinâmico, com um pivô:
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)
Onde so926209_1
, so926209_2
são sua Tabelas 1 e 2
Note que se você tiver vários incidentes em um mês para a mesma pessoa, o seu exemplo não mostra como você quer que manipulados. Este exemplo leva apenas o último incidente no mês.
Outras dicas
Você quer Pivot http://msdn.microsoft.com/en-us/library/ms177410. aspx
Isso soa como uma tarefa relatório. Elaboração de relatórios, muitas vezes referida a partir de uma perspectiva de banco de dados como OLAP, online Aanalytical Processing, tende a variar bastante freqüência de acesso ao banco "tradicional", OLTP (Online Transaction Processing) em que é muitas vezes feita de grandes agregações de dados que abrangem períodos superiores de tempo. Muito freqüentemente, o tipo de agregação a sua procura.
O uso de um Pivot como Tetraneutron sugeriu será suficiente para menores conjuntos de dados. No entanto, como o volume de dados que você precisa para informar sobre cresce, você pode precisar de algo mais avançado. OLAP está prevista no SQL Server Analysis Services (SSAS), disponível em 2005 e 2008. Usando SSAS pode criar repositórios de dados multidimensionais que os dados pré-agregados a partir de qualquer um banco de dados OLTP diretamente, ou a partir de um banco de dados de armazém de dados intermediário. dados multidimensionais (geralmente referidos como cubos), fornecem uma maneira muito mais rápida de acesso o tipo de dados que você pode obter de um pivô, sem interferir com o desempenho do seu processamento de transações padrão em seu banco de dados OLTP.
Se você tiver mais do que uma pequena quantidade de dados que você precisa para relatar, eu recomendo que você verifique SQL Server Analysis Services 2005, OLAP, cubos, e MDX (Multidimensional Extensões para T-SQL.) Há uma learnig maior curva para criar um cubo OLAP, mas uma vez que é criado, os benefícios de ter um pode ser enorme se você tem necessidades de relatórios significativos.
A consulta como isso iria funcionar:
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
Dependendo do seu cliente e quantas vezes você tem que executá-lo, você pode gerar essa consulta. Em SQL este seria parecido com:
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)