2017-06-22 3 views
1

Je grappe un fichier journal pour les enregistrements de transaction que j'insère dans une table qui sera utilisée pour plusieurs tâches d'exploration de données. Chaque enregistrement a (entre autres) un identifiant et un type de transaction, soit une requête, soit une réponse. Une paire requête/réponse aura le même ID.Comment trouver des enregistrements sans correspondance dans une seule table?

Une de mes tâches consiste à trouver toutes les demandes qui n'ont pas de réponse correspondante. J'ai pensé à joindre la table à elle-même, où A.ID = B.ID AND A.type = 'req' et B.type = 'res', mais cela me donne le contraire de ce dont j'ai besoin.

Étant donné que les ID se produiront toujours une ou deux fois, y a-t-il une requête qui sélectionnerait l'ID s'il n'y a qu'une occurrence de cet ID dans la table?

+0

'SELECT * FROM the_table A WHERE N'EXISTE PAS (SELECT * FROM the_table B où A.ID = B.ID AND A.type = 'req' et B.type = 'res'); ' – joop

Répondre

4

Il s'agit d'un type de requête très courant. Vous pouvez essayer d'agréger sur les valeurs ID dans votre tableau en utilisant GROUP BY, puis en conservant les ID qui n'apparaissent qu'une seule fois.

SELECT ID 
FROM yourTable 
GROUP BY ID 
HAVING COUNT(*) = 1 

Si vous voulez aussi retourner les entiers pour ceux ID qui se produisent une seule fois, vous pouvez essayer ceci:

SELECT t1.* 
FROM yourTable t1 
INNER JOIN 
(
    SELECT ID FROM yourTable GROUP BY ID HAVING COUNT(*) = 1 
) t2 
    ON t1.ID = t2.ID 
1

Cela vous donnera ceux qui ont demande, mais pas respose

SELECT * 
FROM your_table A LEFT OUTER JOIN 
your_table B ON A.ID = B.ID 
AND A.type = 'req' and B.type = 'res' 
WHERE B.ID IS NULL 
+0

Maintenant, je montre mon ignorance SQL - si joindre sur A.ID = B.ID, comment B.ID peut-il être NULL et A.ID ne pas être NULL? – Jim

+1

Ceci est le LEFT JOIN, vous allez correspondre A.ID = B.ID au niveau de la jointure, donc s'il y a des enregistrements, l'instruction WHERE sera fausse et ne sélectionnera pas cet enregistrement car il a en fait un type = req. mais si elle n'a pas de type = req, aucun enregistrement de la table B ne sera sélectionné ce qui signifie que B.ID est nul – asmgx

+0

@Jim: Ceci s'appelle une anti-jointure. Il est principalement utilisé dans les SGBD faibles qui ont des problèmes avec les méthodes directes (à savoir «NOT EXISTS» et «NOT IN»). –

2

La voie directe est NOT IN:

select * 
from mytable 
where type = 'req' 
and id not in (select id from mytable where type = 'res'); 

Vous pouvez écrire sur la même chose avec NOT EXISTS, mais la requête devient un peu moins lisible:

select * 
from mytable req 
where type = 'req' 
and not exists (select * from mytable res where type = 'res' and res.id = req.id); 

Et puis il y a des formes d'agrégation que vous pouvez utiliser, par exemple:

select * 
from mytable 
where type = 'req' 
and id in 
(
    select id 
    from mytable 
    group by id 
    having count(case when type = 'res' then 1 end) = 0 
);