即使count为零,MYSQL也会为每个唯一行选择计数

时间:2017-06-17 10:48:40

标签: mysql select count

我很难编写选择,我可以为每个独特的行获得多个计数,我搜索整个网络并写入选择,但它不按我想要的方式工作。 所以,我有两个表横幅和bannerhistory

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

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

2 个答案:

答案 0 :(得分: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

注意/建议:
我认为在你的模式中,在bannerhistory中保留userId是多余的,以防横幅表本身具有id vs user的引用, 所以在bannerhistory中,应该只有bannerId vs ip组合。

答案 1 :(得分: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 ... IFNULLBannerHistory表中缺少的行添加零代替空值。

专业提示:制定缩进查询代码的个人风格,以便您可以在结构化查询语言中看到结构。缩进每个查询所需的额外30秒将在维护代码时自行回报数百次。