2009-02-12 15 views
37

Soy un novato en lo que respecta a la sintaxis SQL.¿Cómo combino 2 declaraciones seleccionadas en una?

Tengo una tabla con una gran cantidad de filas y columnas de curso: P Digamos que tiene este aspecto:

 AAA BBB CCC DDD 
----------------------- 
Row1 | 1 A D X 
Row2 | 2 B C X 
Row3 | 3 C D Z 

Ahora quiero crear una instrucción de selección avanzada que me da este (pseudo SQLish combinado aquí):

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' 

La salida sería:

Test1, 1, A, D, X 
Test2, 2, B, C, X 

¿Cómo combinaría esas dos declaraciones seleccionadas en una sola declaración selecta?

¿Funcionaría si compilé el SQL como a continuación (porque mi propia instrucción SQL contiene una instrucción exists)? Solo quiero saber cómo puedo combinar las selecciones y luego intentar aplicarlas a mi SQL algo más avanzado.

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...) 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...) 




Mi instrucción SQL real es ésta:

select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

que me da resultado. Pero quiero combinarlo con una copia de esta declaración de selección con un AND agregado al final y el campo 'Estado' se cambiaría con una cadena como 'DELETED'.

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
+1

+1 que es una pregunta muy bien hecha –

Respuesta

55

Usted tiene dos opciones aquí. La primera es tener dos conjuntos de resultados que establecerán 'Prueba1' o 'Prueba2' basado en la condición de la cláusula WHERE, y luego UNION juntos:

select 
    'Test1', * 
from 
    TABLE 
Where 
    CCC='D' AND DDD='X' AND exists(select ...) 
UNION 
select 
    'Test2', * 
from 
    TABLE 
Where 
    CCC<>'D' AND DDD='X' AND exists(select ...) 

Esto podría ser un problema, ya que se van para escanear/buscar efectivamente en TABLE dos veces.

La otra solución sería seleccionar de la mesa una vez, y establecer 'Prueba1' o 'Prueba2' basado en las condiciones de la Tabla:

select 
    case 
     when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1' 
     when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2' 
    end, 
    * 
from 
    TABLE 
Where 
    (CCC='D' AND DDD='X' AND exists(select ...)) or 
    (CCC<>'D' AND DDD='X' AND exists(select ...)) 

El truco aquí es que usted tendrá que duplicar la condiciones de filtro en la instrucción CASE y la instrucción WHERE.

+0

Gracias (estoy usando MS SQL Server 2005). Parece que esto es lo que estoy buscando. UNION escanea dos veces, pero puedo vivir con eso. Y no sabía que la declaración CASE podría ser utilizada con anticipación. – Wolf5

9

Si son de la misma tabla, creo UNION es el comando que está buscando.

(Si alguna vez tiene que seleccionar los valores de columnas de diferentes tablas, usted debe buscar en su lugar JOIN ...)

1
select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

UNION 

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 

Tal vez eso sería hacer el truco. Sin embargo, no puedo probarlo desde aquí, y no estoy seguro de qué versión de SQL está trabajando en contra.

1

utilizar un caso en el selecto y uso en el cierre, donde un O

algo como esto, yo no probado, pero debería funcionar, creo ...

select case when CCC='D' then 'test1' else 'test2' end, * 
from table 
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X') 
1

I piensan que es lo que está buscando que:

SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.* 
FROM WorkItems t1 
WHERE (TextField01, TimeStamp) IN(
    SELECT TextField01, MAX(TimeStamp) 
    FROM WorkItems t2 
    GROUP BY t2.TextField01 
) 
AND TimeStamp > '2009-02-12 18:00:00' 

Si estás en Oracle o en MS SQL 2005 y por encima, entonces se podría hacer:

SELECT * 
FROM (
    SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*, 
    ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn 
    FROM WorkItems t1 
) to 
WHERE rn = 1 

, es más eficiente.

2

Gracias por la entrada. Probamos la materia que se ha mencionado aquí y estos son los 2 que se puso a trabajar:

(
select 'OK', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND (BoolField05=1) 
) 
UNION 
(
select 'DEL', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
) 

Y

select 
    case 
     when 
      (BoolField05=1) 
    then 'OK' 
    else 'DEL' 
     end, 
     * 
from WorkItems t1 
Where 
      exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
      AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
      AND TimeStamp>'2009-02-12 18:00:00' 

Cuál sería el más eficiente de estas (edit: la segunda, ya que sólo explora la tabla una vez), y es posible hacerlo aún más eficiente? (BoolField = 1) es realmente una variable (dyn sql) que puede contener cualquier instrucción where en la tabla.

Me estoy ejecutando en MS SQL 2005. Probé los ejemplos de Quassnoi pero no funcionó como esperaba.

+0

Esto es sólido. Gracias :) – Jordon

0
select t1.* from 
(select * from TABLE Where CCC='D' AND DDD='X') as t1, 
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2 

¡Otra forma de hacerlo!

+0

Prueba simple de una sola tabla de columna con 2 filas y usando esa consulta para seleccionar la primera como t1 y la segunda como t2, falla, devuelve solo t1. – Wolf5

Cuestiones relacionadas