SQL - Définir la différence et obtenir des champs qui ne font pas partie de la différence

StackOverflow https://stackoverflow.com/questions/5903291

  •  29-10-2019
  •  | 
  •  

Question

J'ai une requête qui exécute essentiellement quelque chose comme ceci:

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

Dans cet exemple, a, b et c sont les champs clés de cette table. state fait également partie de la clé, et j'essaie de trouver des situations où il y a un enregistrement dans l'état A et non dans l'état B.Il y a un autre champ (pas dans la clé) sur lequel je voudrais signaler, value, qui peut être différent pour le même enregistrement dans différents états. Exemple:

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

Dans ce cas, je suis intéressé par la ligne dont la clé est 1,3,9 où state est A. J'aimerais aussi obtenir la valeur de la colonne value, mais si j'essaye:

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

Ce que je recevrais, ce serait deux lignes:

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

Fondamentalement, je veux avoir value dans le jeu de résultats, mais ne pas participer au minus. J'ai l'impression de manquer quelque chose d'évident ici, mais peut-être que je suis juste trop fatigué pour l'obtenir ...;)

Était-ce utile?

La solution

La manière la plus évidente de procéder est la suivante:

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)

J'ajouterais même un distinct dans la requête externe si les données peuvent avoir des doubles.

Autres conseils

You can join all rows where state = 'A' with the matching ones with 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

...and then pick the rows where there were no match:

 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 

I believe above code would do the trick.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top