#25136: Multiple annotations result in wrong results with MySQL backend ----------------------------------------------+-------------------- Reporter: mdomans | Owner: nobody Type: Bug | Status: new Component: Database layer (models, ORM) | Version: 1.8 Severity: Normal | Keywords: Triage Stage: Unreviewed | Has patch: 0 Easy pickings: 0 | UI/UX: 0 ----------------------------------------------+-------------------- The problem is the difference between the results of **count()** on **entries** relation and **num_entries** if I also want an annotation for **alerts** relation
{{{#!python reports = Report.objects.filter( user=request.user).annotate(num_entries=Count('entries'), num_alerts=Count('alerts')) print report.num_entries, report.entries.count() }}} Yet, this problem did not happen if there was only 1 argument to annotate. What's happening? Well, both **entries** and **alerts** are FK relations, thus they result in this two left outer joins. The SQL is something like this: {{{#!sql SELECT `coverage_reports`.* COUNT(`alerts_alert`.`id`) AS `num_alerts`, COUNT(`coverage_reports_entry`.`id`) AS `num_entries` FROM `coverage_reports_coveragereport` LEFT OUTER JOIN `alerts_alert` ON ( `coverage_reports_coveragereport`.`id` = `alerts_alert`.`coverage_report_id` ) LEFT OUTER JOIN `coverage_reports_entry` ON (`coverage_reports_coveragereport`.`id` = `coverage_reports_entry`.`coverage_report_id` ) WHERE `coverage_reports_coveragereport`.`user_id` = 1 GROUP BY `coverage_reports_coveragereport`.`id` ; }}} This is problematic as joins will duplicate parent records if more than one child record is associated to it. This is what can inflate values from aggregate functions. The fix to this particular query was such: {{{#!sql SELECT reports.id, alerts.num_alerts, entries.num_entries FROM coverage_reports_coveragereport AS reports LEFT JOIN (SELECT coverage_report_id, COUNT(*) AS num_alerts FROM alerts_alert GROUP BY coverage_report_id) AS alerts ON reports.id = alerts.coverage_report_id LEFT JOIN (SELECT coverage_report_id, COUNT(*) AS num_entries FROM coverage_reports_entry GROUP BY coverage_report_id) AS entries ON reports.id = entries.coverage_report_id WHERE reports.user_id = 1 GROUP BY reports.id; }}} -- Ticket URL: <https://code.djangoproject.com/ticket/25136> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/050.31a43e8ffeaba010e86e7a7bb9053dd6%40djangoproject.com. For more options, visit https://groups.google.com/d/optout.