Pregunta

Tengo una consulta que básicamente realiza algo como esto:

select a, b, c
from tab
where tab.state = 'A'
minus
select a, b, c
from tab
where tab.state = 'B'

En este ejemplo, a, b, y c son los campos clave de esta tabla. state También es parte de la clave, y estoy tratando de encontrar situaciones en las que haya un registro en el estado A y no en el estado B. Hay otro campo (no en la clave) en el que me gustaría informar, value, eso podría ser diferente para el mismo registro en diferentes estados. Ejemplo:

a  b  c  state  value
---------------------
1  1  1  A      12
1  2  2  A      1002
1  3  9  A      43
1  1  1  B      17.34
1  2  2  B      1002

En este caso, estoy interesado en la fila cuya clave es 1,3,9 Donde el estado está A. También me gustaría obtener el valor del value columna, pero si lo intento:

select a, b, c, value
from tab
where tab.state = 'A'
minus
select a, b, c, value
from tab
where tab.state = 'B'

Lo que me devolverían son dos filas:

a  b  c    value
----------------
1  1  1      12
1  3  9      43

Básicamente, quiero tener value en el conjunto de resultados, pero no participar en el minus. Siento que me estoy perdiendo algo obvio aquí, pero tal vez estoy demasiado cansado para conseguirlo ...;)

¿Fue útil?

Solución

La forma obvia de hacer esto es así:

select a, b, c, value
from tab
where tab.state = 'A' and not exists (
  select 1                          -- let the optimizer do its thing
  from tab ti
  where tab.state = 'B' and ti.a=tab.a and ti.b=tab.b and ti.c=tab.c)

Incluso agregaría un distinct en la consulta externa si los datos pueden tener dobles.

Otros consejos

Puedes unirte a todas las filas donde state = 'A' con los coincidentes con state = 'B'...

SELECT t1.a, t1.b, t1.c, t1.value, t2.value v2
FROM (SELECT a, b, c, value FROM tab WHERE state = 'A') t1
     LEFT JOIN (SELECT a, b, c, value FROM tab WHERE state = 'B') t2
            ON t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c

... y luego elige las filas donde no hubo partido:

 SELECT a, b, c, value
 FROM ( /* previous query */ )
 WHERE v2 IS NULL
SELECT a,
  b,
  c,
  value
FROM tab tab1
INNER JOIN
  (SELECT a, b, c FROM tab WHERE tab.state = 'A'
  MINUS
  SELECT a, b, c FROM tab WHERE tab.state = 'B'
  ) tab2
ON tab1.a  = tab2.a
AND tab1.b = tab2.b
AND tab1.c = tab2.c 

Creo que el código anterior haría el truco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top