2017-06-17 40 views
3

我在编写select时遇到了困难,我可以为每个唯一行获取多个计数,我搜索了整个网络并编写了选择,但它并不按我想要的方式工作。 所以,我有两个表的横幅和bannerhistory即使计数为零,每个唯一行的MYSQL选择计数

banners 
Id UserId BannerName 
167 35  Polly 
168 35  Joke 
169 21  Kim 
170 35  Buck 
................ 
BannerHistory 
BannerId UserId IP 
167  35  123asd123 
167  35  123asd123 
168  35  BBB123sss 
....................... 

So my query is: 
SELECT 
banners.Banner_Name, 
banners.Counter, 
banners.ClickCounter, 
COUNT(DISTINCT(bannerhistory.Ip)) 
FROM 
bannerhistory 
    INNER JOIN 
    banners 
    ON bannerhistory.BannerId = banners.ID 
    WHERE 
    bannerhistory.BannerId IN 
    (
     SELECT 
    bannerhistory.BannerId 
    FROM 
    bannerhistory 
     WHERE 
    bannerhistory.UserId = $ UserId 
     ) 
     GROUP BY 
     banners.Banner_Name 

我想我要分别统计不同的IP-S为每个横幅广告userId的所有bannerNames。我的代码不工作因为它得到第一个横幅不同(计数(Ip))为每个横幅,我的意思是几乎总是计数是相同的。任何人都可以帮助纠正我的查询?或者告诉我不同​​的方法。 不用担心计数器和clickcounter列,它们在banners表中没有什么值得在那里计算,只是让它们得到它们。 对不起,我的英文。

回答

1

这种情况下,您想要在子查询中执行聚合(COUNT ... GROUP BY)操作,然后执行加入。子查询看起来像这样,并获得历史表中每个用户和横幅ID组合的不同IP值的数量。 (http://sqlfiddle.com/#!9/c502bb/3/0

  SELECT BannerId, UserId, COUNT(DISTINCT IP) BannerCount 
       FROM bannerHistory 
      GROUP BY BannerId, UserId 

然后你就可以加入,就好像它是一个虚拟表,你banner表,并使用WHERE选择所需的用户ID。 (http://sqlfiddle.com/#!9/c502bb/2/0

SELECT b.Id, B.UserId, b.BannerName, c.BannerCount 
    FROM banner B 
    JOIN (
      SELECT BannerId, UserId, COUNT(DISTINCT IP) BannerCount 
       FROM bannerHistory 
      GROUP BY BannerId, UserId 
     ) C ON B.Id = c.BannerId AND B.UserId = C.UserId 
WHERE B.UserId = 35 

注意,MySQL的查询规划一般是足够聪明的子查询也能有效地对付WHERE条款。

编辑最后,一个普通的内部JOIN抑制与ON条件不匹配的行。要保持你的banner表的每一行,你需要使用LEFT JOIN。 (http://sqlfiddle.com/#!9/c502bb/4/0

SELECT b.Id, B.UserId, b.BannerName, IFNULL(c.BannerCount, 0) BannerCount 
    FROM banner B 
    LEFT JOIN (
      SELECT BannerId, UserId, COUNT(DISTINCT IP) BannerCount 
       FROM bannerHistory 
      GROUP BY BannerId, UserId 
     ) C ON B.Id = c.BannerId AND B.UserId = C.UserId 
WHERE B.UserId = 35 

注意使用SELECT ... IFNULL把零到位空值从BannerHistory表中缺少行。

临提示:开发缩进您的查询代码的个人风格,所以你可以在结构查询语言看结构。在维护代码时,缩进每个查询所花费的额外30秒将自行偿还数百倍。

+0

谢谢伟大的答案和其他技巧,像魅力工作,不知道'IFNULL' – temo

2

尝试使用下面的查询:

Select b.Id,b.UserId,h.ips_count from banners b inner join 
(select BannerId,count(distinct ip) as ips_count 
from bannerhistory group by BannerId) h on b.Id = h.BannerId 

注意/建议:
我想在你的模式,保持用户id在bannerhistory是多余的,万一横幅表本身所具有的ID的这个参考vs用户, 所以在bannerhistory中,应该只有bannerId vs ip组合。

+0

谢谢你的回答,我保留userId在bannerhistory为不同的目的,但谢谢你的额外提示。事情是,我已经改变了你的代码来获取一个userId的信息:'从横幅b选择b.Id,b.UserId,h.ips_count b内连接 (从Bannerhistory WHERE选择BannerId,count(distinct ip)作为ips_count bannerHistory.UserId = 38由BannerId分组)h上b.Id = h。BannerId'。我没有得到所有的横幅,我没有提到我的错,并非所有的横幅都在横幅历史上,但它们可能会出现。或者我可能改错了。 – temo