如何连接3个表并从2个表中计算正确的字段总数,没有重复的行?

时间:2016-01-11 01:17:25

标签: sql postgresql

我有表A,B,C。表A链接到B,表A链接到C.我想加入3个表,找到B.cost的总和和C.clicks的总和。但是,它没有给我预期的值,当我选择没有group by的所有内容时,它显示重复的行。我期望B中的行值汇总为单个总和,并且C中的行值汇总为单个总和。

我的查询看起来像

select A.*, sum(B.cost), sum(C.clicks) from A 
join B
left join C
group by A.id
having sum(cost) > 10

我尝试按B.a_idC.another_field_in_a进行分组,但这不起作用。

这是一个DB小提琴,包含所有数据和完整查询:

  

http://sqlfiddle.com/#!9/768745/13

注意sum字段是如何大于各个表的总和的?我希望总和相等,只包含表B和C的行一次。我也尝试添加distinct,但这并没有帮助。

我正在使用Postgres。 (虽然这个小提琴设置为MySQL。)最后我想使用having子句根据它们的总和来选择行。此查询将针对数百万行。

3 个答案:

答案 0 :(得分:1)

如果我理解逻辑正确,问题是由两个连接引起的笛卡尔积。您的查询有点难以理解,但我认为使用相关子查询可以更好地处理意图:

select k.*,
       (select sum(cost)
        from ad_group_keyword_network n
        where n.event_date >= '2015-12-27' and
              n.ad_group_keyword_id = 1210802 and
              k.id = n.ad_group_keyword_id
       ) as cost,
       (select sum(clicks)
        from keyword_click c
        where (c.date is null or c.date >= '2015-12-27') and
              k.keyword_id = c.keyword_id               
       ) as clicks
from ad_group_keyword k
where k.status = 2 ;

Here是相应的SQL小提琴。

编辑:

子选择应该比未聚合数据上的group by更快。但是,您需要正确的索引:ad_group_keyword_network(ad_group_keyword_id, ad_group_keyword_id, event_date, cost)keyword_click(keyword_id, date, clicks)

答案 1 :(得分:1)

我找到了这个(MySQL joining tables group by sum issue)并创建了一个像这样的查询

select * 
from A
join (select B.a_id, sum(B.cost) as cost 
  from B 
  group by B.a_id) B on A.id = B.a_id
left join (select C.keyword_id, sum(C.clicks) as clicks
  from C
  group by C.keyword_id) C on A.keyword_id = C.keyword_id
group by A.id
having sum(cost) > 10

我不知道它是否有效。我不知道它是否比戈登的效率更高或更低。我跑了两个查询,这个看起来更快,27秒对2分35秒。这是一个小提琴:http://sqlfiddle.com/#!15/c61c74/10

答案 2 :(得分:1)

只需将第二个表的聚合分割为子查询,如下所示:

http://sqlfiddle.com/#!9/768745/27

select ad_group_keyword.*, SumCost, sum(keyword_click.clicks) 
from ad_group_keyword 
left join keyword_click on ad_group_keyword.keyword_id = keyword_click.keyword_id 
left join (select ad_group_keyword.id, sum(cost) SumCost
           from ad_group_keyword join ad_group_keyword_network on ad_group_keyword.id = ad_group_keyword_network.ad_group_keyword_id
           where event_date >= '2015-12-27' 
           group by ad_group_keyword.id
           having sum(cost) > 20
) Cost on Cost.id=ad_group_keyword.id
where  
(keyword_click.date is null or keyword_click.date >= '2015-12-27') 
and status = 2 
group by ad_group_keyword.id