2009-05-20 19 views
5

tenemos una tabla que es de la forma:Individual SQL SELECT devuelve varias filas de la fila de una tabla

ID,Value1,Value2,Value3 
1,2,3,4 

Tenemos que transformar esto en.

ID,Name,Value 
1,'Value1',2 
1,'Value2',3 
1,'Value3',4 

¿Hay una forma inteligente de hacer esto en una instrucción SELECT (es decir, sin sindicatos)? Los nombres de columna Value1, Value2 y Value3 son fijos y constantes.

La base de datos es Oracle 9i.

+0

¿Qué servidor DB está utilizando? –

+0

¿Hay columnas 1,2,3,4 o valores de datos? –

+1

La manera más inteligente que puedo pensar es rediseñar su base de datos para que esté normalizada :) –

Respuesta

3

Esto funciona en Oracle 10g:

select id, 'Value' || n as name, 
     case n when 1 then value1 when 2 then value2 when 3 then value3 end as value 
from (select rownum n 
     from (select 1 from dual connect by level <= 3)) ofs, t 

creo Oracle 9i tenía consultas recursivas? De todos modos, estoy bastante seguro de que tiene soporte CASE, por lo que incluso si no tiene consultas recursivas, puede hacer "(seleccione 1 de dual union all select 2 from dual union all select 3 from dual) ofs". El abuso de consultas recursivas es un poco más general, para Oracle. (Sin embargo, el uso de uniones para generar filas es portátil para otros DB)

+0

+1 para el escaneo de una sola tabla. Consultas recursivas de WRT: Oracle ha tenido consultas jerárquicas desde 7, pero solo introdujo la cláusula WITH recursiva en 11gR2. –

9

Dé un union una oportunidad.

select ID, 'Value1' as Name, Value1 as Value from table_name union all 
select ID, 'Value2', Value2 as Value from table_name union all 
select ID, 'Value3', Value3 as Value from table_name 

order by ID, Name 

usando union all significa que el servidor no llevará a cabo un distinct (que es implícita en union operaciones). No debería hacer ninguna diferencia con los datos (ya que su ID debería ser ESPERAMENTE diferente), pero podría acelerarlo un poco.

+0

Bueno, así es como lo haría, me gusta la optimización UNION ALL. Error menor: en el ejemplo, no hay ningún valor4. Supongo que una forma alternativa es anular, dependiendo de si el DB admite esta funcionalidad. – RichardOD

+0

¡Usar 'union all' definitivamente no hará ninguna diferencia en el resultado ya que 'Value1', 'Value2' y 'Value3' son todos distintos! Pero evitará que el DB trate inútilmente de uniquificar las filas. – araqnid

+0

¡Buena respuesta, pero pregunta por un camino * sin * uniones! –

2

Puede hacerlo de esta manera, pero no es bastante:

SELECT id,'Value 1' AS name,value1 AS value FROM mytable 
UNION 
SELECT id,'Value 2' AS name,value2 AS value FROM mytable 
UNION 
SELECT id,'Value 3' AS name,value3 AS value FROM mytable 
2

unificante tres sentencias de selección debe hacer el truco:

SELECT ID, 'Value1', Value1 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value2', Value2 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value3', Value3 AS Value 
FROM TABLE 
0

Si está utilizando SQL Server 2005 + entonces puede utilizar UNPIVOT

CREATE TABLE #tmp (ID int, Value1 int, Value2 int, Value3 int) 

INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4) 

SELECT 
    * 
FROM 
    #tmp 

SELECT 
    * 
FROM 
    #tmp 
UNPIVOT 
(
    [Value] FOR [Name] IN (Value1, Value2, Value3) 
) uPIVOT 

DROP TABLE #tmp 
-1

para SQL Server, considere UNPIVOT como una alternativa a la unión:

SELECT id, value, colname 
FROM #temp t 
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X 

Esto también devolverá el nombre de la columna. No estoy seguro de para qué se usa la X, pero no puedes dejarla de lado.

0

UNION ALL, como otros han sugerido, es probablemente su mejor apuesta en SQL. También es posible que desee considerar manejar esto en la parte delantera, dependiendo de cuáles sean sus requisitos específicos.

-1

Pruebe esto:

CTE crea una tabla temporal con 4 valores. Puede ejecutar esto como está en cualquier base de datos.

with TEST_CTE (ID) as 

(select * from (select '1' as a) as aa union all 
select * from (select '2' as b) as bb union all 
select * from (select '3' as c) as cc union all 
select * from (select '4' as d) as dd) 

select a.ID, 'Value'|| a.ID, b.ID 
from TEST_CTE a, TEST_CTE b 
where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID) 

Aquí es el conjunto de resultados:

1 Value1 2 

2 Value2 3 

3 Value3 4 

Enjoy!

Algunas ideas del pasado.

^^^ La sintaxis de CTE puede ser diferente en Oracle. Solo pude ejecutarlo en Teradata. Puede sustituirlo por tabla temporal o corregir la sintaxis para que sea compatible con Oracle. La instrucción select es simple y simple SQL que funcionará en cualquier base de datos.

^^^ Otra cosa a tener en cuenta. Si el campo ID es numérico, es posible que deba convertirlo en CHAR para concatenarlo con "Value".

+0

-1 Esto no se ejecuta en Oracle. –

+0

Acabo de agregar algunos comentarios a mi publicación. –

0

La sintaxis CTE puede ser diferente para Oracle (la ejecuté en Teradata), pero solo utilicé CTE para proporcionar datos de prueba, esos 1 2 3 y 4. En su lugar, puede usar tabla temporal. La instrucción de selección real es simple y vainilla de SQL y lo será en cualquier base de datos relacional.

Cuestiones relacionadas