max
max

Reputation: 3736

wrong count on the multiple joins with the same table

i have 2 tables

1 - coupons

2 - tractions

for each coupon there might be couple of rows in tractions table I want to have list of all coupons and count of its tractions under different condition

    SELECT `coupons`.`id` ,
            count( tractions_all.id ) AS `all` , 
            count( tractions_void.id ) AS void, 
            count( tractions_returny.id ) AS returny,
            count( tractions_burned.id ) AS burned
      FROM `coupons`
               LEFT JOIN `tractions` AS `tractions_all` 
                         ON `coupons`.`id` = `tractions_all`.`coupon_parent`
               LEFT JOIN `tractions` AS `tractions_void` 
                         ON `coupons`.`id` = `tractions_void`.`coupon_parent`
                         AND `tractions_void`.`expired` =1
               LEFT JOIN `tractions` `tractions_returny` 
                         ON `tractions_returny`.`coupon_parent` = `coupons`.`id`
                         AND `tractions_returny`.`expired` =11
               LEFT JOIN `tractions` `tractions_burned` 
                         ON `tractions_burned`.`coupon_parent` = `coupons`.`id`
                         AND `tractions_burned`.`expired` =0
                         AND '2014-02-12'
     WHERE `coupons`.`parent` =0
  GROUP BY `coupons`.`id`

right now only one of my coupons has 2 traction on both are burned traction other coupons have no tractions at all

here is the result

enter image description here

as you can see coupon with id=13 has 4 traction while it should be 2 ... what am i doing wrong ? if i remove the last join it works fine and i get 2

Upvotes: 0

Views: 64

Answers (1)

Gordon Linoff
Gordon Linoff

Reputation: 1270713

You are aggregating along multiple dimensions at one time, resulting in a cartesian product for each id.

If your data volume is not very large, the easiest way to fix this is using distinct:

SELECT `coupons`.`id` ,
       count(distinct tractions_all.id ) AS `all` , 
       count(distinct tractions_void.id ) AS void, 
       count(distinct tractions_returny.id ) AS returny,
       count(distinct tractions_burned.id ) AS burned

If your data is large, then you will probably need to aggregate values as subqueries first and then do the joins.

Upvotes: 1

Related Questions