2009-06-03 18 views
14

Estoy trabajando con una tabla en la que hay varias filas que necesito pivotar en columnas. Entonces, el pivote es la solución perfecta para esto, y funciona bien cuando todo lo que necesito es un campo. Necesito devolver varios campos basados ​​en el pivote. Aquí está el código de pseudo con detalles quitó:Pivote de columna múltiple en T-SQL

SELECT 
    field1, 
    [1], [2], [3], [4] 
FROM 
    (
    SELECT 
    field1, 
    field2, 
    (ROW_NUMBER() OVER(PARTITION BY field1 ORDER BY field2)) RowID 
    FROM tblname 
) AS SourceTable 
PIVOT 
    (
    MAX(field2) 
    FOR RowID IN ([1], [2], [3], [4]) 
) AS PivotTable; 

La sintaxis anterior funciona muy bien, pero ¿qué hago cuando necesito para obtener información adicional encontrado en field3, campo4 ....?

+2

¿Qué necesita exactamente? –

+0

Lo intenté, trabajando bien para mí (3er enfoque en el blog). http://dba.stackexchange.com/questions/65786/query-pivot-multiple-columns-variable-number-of-rows – JayaPrakash

Respuesta

11

reescritura utilizando MAX (CASE ...) y GROUP BY:

select 
    field1 
, [1] = max(case when RowID = 1 then field2 end) 
, [2] = max(case when RowID = 2 then field2 end) 
, [3] = max(case when RowID = 3 then field2 end) 
, [4] = max(case when RowID = 4 then field2 end) 
from (
    select 
    field1 
    , field2 
    , RowID = row_number() over (partition by field1 order by field2) 
    from tblname 
) SourceTable 
group by 
    field1 

Desde allí se pueden añadir en field3, campo4, etc.

+0

Lo que terminé haciendo fue usar sentencias CASe en un CTE para rellenar esta tabla derivada, a la que uní con criterios adicionales. Aquí es el CTE: – websch01ar

+0

Con cteSec como ( \t SELECT \t vSec.ID, \t --Secretary 1 ----------------------- - \t MAX ( \t \t CASE vSec.RowID \t \t CUANDO 1 ENTONCES vSec.field1 \t \t ELSE '' \t \t FIN \t) [SEC_OfficePhone1], \t MAX ( \t \t CASE vSec.RowID \t \t CUANDO 1 ENTONCES vSec.campo2 \t \t ELSE '' \t \t FIN \t) [SEC_OfficeFax1], \t \t DE \t ( \t --Este SERÁ EL INTERIOR consulta (que asigna filas para secretarias) \t SELECT TOP 100 PERCENT \t \t campo1, campo2, ID \t \t (ROW_NUMBER() OVER (PARTITION BY vs.ID ORDER BY vs.ID2)) rowid \t DE tblname vs \t ORDER BY vs.ID, ID2 \t) VSEC \t GROUP BY \t vSec.ID ) – websch01ar

+0

Así que a través de este método que he hardcoded el número de columnas que estoy esperando. En general, preferiría hacer esto de forma dinámica, ya que está destinado a cambiar. Pero como compañía, nos estamos enfocando en la reducción general, así que no veo la necesidad de más de cuatro secretarias por jefe ... Le doy el crédito porque su publicación me llevó a escribir el caso 20 declaraciones. Esto funciona como un amuleto con una respuesta de menos de segundo. – websch01ar

1

No estoy seguro de si está utilizando el servidor MS SQL, pero si lo está ... Es posible que desee echar un vistazo a la funcionalidad CROSS APPLY del motor. Básicamente, le permitirá aplicar los resultados de una UDF con valores de tabla a un conjunto de resultados. Esto requeriría que coloque su consulta dinámica en un conjunto de resultados con valores de tabla.

http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/sql-server-cross-apply.aspx

+0

-1 No se puede ver la relación con la pregunta – Andomar

+0

La pregunta está etiquetada y titulada como T-SQL . Ese es el dialecto MS .... – RolandTumble

+0

También es dialecto de Sybase. –

1

envolver su instrucción SQL con algo así como:

select a.segment, sum(field2), sum(field3) 
from (original select with case arguments) a 
group by a.segment 

debe colapsar sus resultados en una sola fila, agrupados en el campo1.

1

El truco para hacer múltiples pivotes sobre un row_number es modificar esa secuencia número de fila para almacenar tanto la secuencia y el número de campo. Aquí hay un ejemplo que hace lo que quiere con múltiples instrucciones PIVOT.

-- populate some test data 
if object_id('tempdb..#tmp') is not null drop table #tmp 
create table #tmp (
    ID int identity(1,1) not null, 
    MainField varchar(100), 
    ThatField int, 
    ThatOtherField datetime 
) 

insert into #tmp (MainField, ThatField, ThatOtherField) 
select 'A', 10, '1/1/2000' union all 
select 'A', 20, '2/1/2000' union all 
select 'A', 30, '3/1/2000' union all 
select 'B', 10, '1/1/2001' union all 
select 'B', 20, '2/1/2001' union all 
select 'B', 30, '3/1/2001' union all 
select 'B', 40, '4/1/2001' union all 
select 'C', 10, '1/1/2002' union all 
select 'D', 10, '1/1/2000' union all 
select 'D', 20, '2/1/2000' --union all 

-- pivot over multiple columns using the 1.1, 1.2, 2.1, 2.2 sequence trick 
select 
    MainField, 
    max([1.1]) as ThatField1, 
    max([1.2]) as ThatOtherField1, 
    max([2.1]) as ThatField2, 
    max([2.2]) as ThatOtherField2, 
    max([3.1]) as ThatField3, 
    max([3.2]) as ThatOtherField3, 
    max([4.1]) as ThatField4, 
    max([4.2]) as ThatOtherField4 
from 
    (
     select x.*, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.1' as ThatFieldSequence, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.2' as ThatOtherFieldSequence 
     from #tmp x 
    ) a 
    pivot (
     max(ThatField) for ThatFieldSequence in ([1.1], [2.1], [3.1], [4.1]) 
    ) p1 
    pivot (
     max(ThatOtherField) for ThatOtherFieldSequence in ([1.2], [2.2], [3.2], [4.2]) 
    ) p2 
group by 
    MainField