web-dev-qa-db-fra.com

Compter le nombre de lignes jointes dans la jointure gauche

J'essaie d'écrire une requête agrégée en SQL qui renvoie le nombre de tous les enregistrements joints à un enregistrement donné dans une table; Si aucun enregistrement n'a été joint à l'enregistrement donné, le résultat de cet enregistrement doit être 0:

Les données

Ma base de données ressemble à ceci (je ne peux malheureusement pas changer la structure):

MESSAGE
----------------------------------------------
MESSAGEID   SENDER        SUBJECT
----------------------------------------------
1           Tim           Rabbit of Caerbannog
2           Bridgekeeper  Bridge of Death

MESSAGEPART
----------------------------------------------
MESSAGEID   PARTNO        CONTENT
----------------------------------------------
1           0             (BLOB)
1           1             (BLOB)
3           0             (BLOB)

(MESSAGEPART a un composite PRIMARY KEY("MESSAGEID", "PARTNO"))

Sortie désirée

Compte tenu des données ci-dessus, je devrais obtenir quelque chose comme ceci:

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
2           0

Il semble évident que je dois faire une jointure gauche sur la table MESSAGE, mais comment puis-je retourner un nombre de 0 Pour les lignes où les colonnes jointes de MESSAGEPART sont NULL? J'ai essayé ce qui suit:

Logique

J'ai essayé

SELECT m.MESSAGEID, COUNT(*) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

Cependant, cela renvoie

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
2           1

J'ai aussi essayé

SELECT mp.MESSAGEID, COUNT(*) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY mp.MESSAGEID;

mais cela revient

MESSAGEID   COUNT(*)
-----------------------------------------------
1           2
            1

Qu'est-ce que je fais mal ici?

30
errantlinguist

Que diriez-vous quelque chose comme ça:

SELECT m.MESSAGEID, sum((case when mp.messageid is not null then 1 else 0 end)) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

La fonction COUNT () comptera chaque ligne, même si elle a null. En utilisant SUM () et CASE, vous ne pouvez compter que des valeurs non nulles.

EDIT: Une version plus simple tirée du commentaire du haut:

SELECT m.MESSAGEID, COUNT(mp.MESSAGEID) FROM MESSAGE m
LEFT JOIN MESSAGEPART mp ON mp.MESSAGEID = m.MESSAGEID
GROUP BY m.MESSAGEID;

J'espère que ça t'as aidé.

51
Mark J. Bobak

Vous premier voulez compter dans votre table messaepart avant de rejoindre, je pense. Essaye ça:

   SELECT m.MessageId
        , COALESCE(c, 0) as myCount
     FROM MESSAGE m
LEFT JOIN (SELECT MESSAGEID
                , count(*) c 
             FROM MESSAGEPART 
            GROUP BY MESSAGEID) mp
       ON mp.MESSAGEID = m.MESSAGEID
9
oerkelens