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) |
SELECT DISTINCT
! ;-)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 :)
Le select distinct supprime les doublons, ma remarque concernait juste la fin de l’article…
SELECT COUNT(*) FROM Massage GROUP BY FINISH
ou mieux
SELECT FINISH,COUNT(*) FROM Massage GROUP BY FINISH
@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.
@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
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
Bon, on était pas loin,
qs.query.sql_with_params()
donne :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
Oui, j’ai fais ça avec un projet en cours.