Compter les doublons avec l’ORM Django | Sam & Max: Python, Django, Git et du cul

Compter les doublons avec l’ORM Django

GROUP BY et HAVING sont assez peu intuitifs en SQL, et encore moins avec l’ORM Django.

Voici donc la recette pour compter le nombre d’occurrences des valeurs d’un champ, pour par exemple trouver les doublons.

En supposant une table Massage avec une valeur finish :

ID         FINISH
1          manuel
2          oral
3          oral
4          oral
>>> Massage.objects.values('finish').annotate(count=Count('id'))
{'manuel': 2, 'oral': '9': 'rectal': 1, 'paradoxal': -1}

Pour obtenir uniquement les doublons, il suffit de filtrer pour avoir les valeurs qui ont un count plus grand que 1 :

Massage.objects.values('finish').annotate(count=Count('id')).filter(count__gt=1)

  11 comments for “Compter les doublons avec l’ORM Django

  1. 22/11/2013 at 09:05

    SELECT DISTINCT ! ;-)

  2. foxmask
    22/11/2013 at 09:27

    le select distinct retourne qu’une occurence non ? là il veut les compter , ou j’ai pas compris.

    @sam : pour ma culture, ca donne quoi la requete SQL complete de tes 2 exemples ? peut-etre j’aurai une remarque en fonction de ca :)

  3. 22/11/2013 at 09:33

    Le select distinct supprime les doublons, ma remarque concernait juste la fin de l’article…

  4. kikine
    22/11/2013 at 10:29

    SELECT COUNT(*) FROM Massage GROUP BY FINISH

  5. kikine
    22/11/2013 at 10:34

    ou mieux
    SELECT FINISH,COUNT(*) FROM Massage GROUP BY FINISH

  6. Sam
    22/11/2013 at 10:37

    @bendem Le but n’est pas de supprimer les doublons, mais de les trouver.

    @kikine : pas sur, il faut regarder ce que l’ORM genère, ce n’est pas un humain.

    @foxmask, si j’y pense je regarderai.

  7. Zanguu
    22/11/2013 at 10:51

    @bendem, pour m’être régulièrement cassé le cul avec des requêtes à la con, si le GROUP BY est “peu intuitif” alors le DISTINCT j’en parle même pas. Et Il ne fait pas le travail d’un having comme le sous entend ton dernier message

    @foxmask, environ : Massage.objects.values('finish').annotate(total=Count('finish'))
    donne
    SELECT finish, count(*) 'total'
    FROM massage
    GROUP BY finish

    Et : Massage.objects.values('finish').annotate(total=Count('finish')).filter(total__gt=1)
    donne
    SELECT finish, count(*)
    FROM massage
    GROUP BY finish
    HAVING count(*) > 1

    Sachant qu’on peut apparement aussi utiliser :
    qs = Massage.objects.all()
    qs.query.group_by = ['finish']
    qs.query.having = ['count(finish) > 1']

    ps: en sql le count(*) et le count(finish) avec une clause GROUP BY reviennent (dans 99% des cas) au même

  8. N
    22/11/2013 at 21:34

    Ah tiens, je découvre d’autres façons de l’écrire, moi je fais ça:
    SELECT finish, count(*) as c FROM massage GROUP BY finish HAVING c > 1

  9. Sam
    24/11/2013 at 08:41

    Bon, on était pas loin, qs.query.sql_with_params() donne :

    SELECT "massage_massage"."finish", COUNT("massage_massage"."id") AS "count" FROM "massage_massage" GROUP BY "massage_massage"."finish"'
  10. zanguu
    25/11/2013 at 08:44

    dans le count, il faudrait un expert bdd pour savoir s’il y a une vraie différence de perf mais sur les résultats ça ne change pas grand chose d’y mettre un ‘*’ ou ‘finish’

    par contre tu as oublié de changer le nom de ta table dans le group by ? parce que là je vois pas bien d’où viens ce nom

  11. Sam
    25/11/2013 at 10:53

    Oui, j’ai fais ça avec un projet en cours.

Leave a Reply

Your email address will not be published. Required fields are marked *