2010-04-21 14 views
15

Tengo algunos problemas al intentar realizar una consulta. Tengo dos tablas, una con información de elementos y otra con registros relacionados con los elementos de la primera tabla. La idea es colocar en la misma fila la información del elemento más varios registros de información.¿Es posible reutilizar subconsultas?

estructura puede ser explicar así:

table [ id, name ] 
[1, '1'], [2, '2'] 

table2 [ id, type, value ] 
[1, 1, '2009-12-02'] 
[1, 2, '2010-01-03'] 
[1, 4, '2010-01-03'] 
[2, 1, '2010-01-02'] 
[2, 2, '2010-01-02'] 
[2, 2, '2010-01-03'] 
[2, 3, '2010-01-07'] 
[2, 4, '2010-01-07'] 

Y esto es quieren me gustaría lograr:

result [id, name, Column1, Column2, Column3, Column4] 

[1, '1', '2009-12-02', '2010-01-03', , '2010-01-03'] 
[2, '2', '2010-01-02', '2010-01-02', '2010-01-07', '2010-01-07'] 

La consulta siguiente obtiene el resultado correcto, pero me parece extremadamente ineficiente , teniendo que iterar table2 para cada columna. ¿Sería posible de todos modos hacer una subconsulta y reutilizarla?

SELECT 
     a.id, 
     a.name, 
     (select min(value) from table2 t where t.id = subquery.id and t.type = 1 group by t.type) as Column1, 
     (select min(value) from table2 t where t.id = subquery.id and t.type = 2 group by t.type) as Column2, 
     (select min(value) from table2 t where t.id = subquery.id and t.type = 3 group by t.type) as Column3, 
     (select min(value) from table2 t where t.id = subquery.id and t.type = 4 group by t.type) as Column4 
FROM 
     (SELECT distinct id 
     FROM table2 t 
     WHERE (t.type in (1, 2, 3, 4)) 
      AND t.value between '2010-01-01' and '2010-01-07') as subquery 
     LEFT JOIN table a ON a.id = subquery.id 
+2

Qué es esto en la base de datos? ¿Y qué versión de la base de datos (por ejemplo, sql server 2000, 2005 o 2008?) –

+0

Posible duplicado de [¿Cómo reutilizar una consulta secundaria en sql?] (Http://stackoverflow.com/questions/14987317/how-to-reuse -a-sub-query-in-sql) –

Respuesta

20

Puede tomar las agregaciones a cabo en un CTE (expresión de tabla común):

with minima as (select t.id, t.type, min(value) min_value 
       from table2 t 
       where t.type in (1,2,3,4) 
       group by t.id, t.type) 
select a.id, a.name, 
     (select min_value from minima where minima.id = subquery.id and minima.type = 1) as column1, 
     (select min_value from minima where minima.id = subquery.id and minima.type = 2) as column2, 
     (select min_value from minima where minima.id = subquery.id and minima.type = 3) as column3, 
     (select min_value from minima where minima.id = subquery.id and minima.type = 4) as column4 
from (select distinct id from table2 t where t.type in (1,2,3,4) and t.value between '2010-01-01' and '2010-01-07') as subquery 
    left join a on a.id = subquery.id 

si esto es realmente ningún beneficio (o incluso compatibles) o no depende de su entorno y conjunto de datos, por supuesto.

Otro enfoque:

select xx.id, a.name, xx.column1, xx.column2, xx.column3, xx.column4 
from (
     select id, 
      max(case type when 1 then min_value end) as column1, 
      max(case type when 2 then min_value end) as column2, 
      max(case type when 3 then min_value end) as column3, 
      max(case type when 4 then min_value end) as column4 
     from (select t.id, t.type, min(value) min_value 
      from table2 t 
      where t.type in (1,2,3,4) 
      group by t.id, t.type) minima 
     group by id 
) xx left join a on a.id = xx.id 
order by 1 
5

Algunos de los productos más nuevos de bases de datos (Oracle, SQL Server 2005, SQL Server 2008 y así sucesivamente) proporcionan la capacidad de crear expresiones de tabla comunes (CTE por sus siglas). Con eso se podría volver a usar una sub consulta de este modo:

With Subquery As 
    (
    Select Id 
     , Min(Case When T.TypeId = 1 Then Value End) As MinType1 
     , Min(Case When T.TypeId = 2 Then Value End) As MinType2 
     , Min(Case When T.TypeId = 3 Then Value End) As MinType3 
     , Min(Case When T.TypeId = 4 Then Value End) As MinType4 
    From Table2 As T 
    Where T.Type In(1,2,3,4) 
     And T.Value Between '2010-01-01' And '2010-01-07' 
    Group By Id 
    ) 
Select A.Id, A.Name, S.MinType1, S.MinType2, S.MinType3, S.MinType4 
From Subquery As S 
    Left Join Table As A 
     On A.Id = S.Id 

Concedido esto no sería muy diferente a:

Select A.Id, A.Name, S.MinType1, S.MinType2, S.MinType3, S.MinType4 
From (
     Select Id 
      , Min(Case When T.TypeId = 1 Then Value End) As MinType1 
      , Min(Case When T.TypeId = 2 Then Value End) As MinType2 
      , Min(Case When T.TypeId = 3 Then Value End) As MinType3 
      , Min(Case When T.TypeId = 4 Then Value End) As MinType4 
     From Table2 As T 
     Where T.Type In(1,2,3,4) 
      And T.Value Between '2010-01-01' And '2010-01-07' 
     Group By Id 
     ) As S 
    Left Join Table As A 
     On A.Id = S.Id