Compter les doublons avec l’ORM Django 11


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)

Leave a Comment

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

11 thoughts on “Compter les doublons avec l’ORM Django

  • foxmask

    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 :)

  • Sam Post author

    @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.

  • Zanguu

    @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

  • N

    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

  • Sam Post author

    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"'
  • zanguu

    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