2016-05-15 56 views
2

我试图将一个广告的性能报告放在一起,显示它在一天中的观看次数和点击次数。视图和点击被存储在具有不同结构的单独表格中,所以我认为我必须执行联合。两个表上的MySQL联盟,其中一个带有时间戳,另一个带有日期

我已阅读并理解this fantastic piece。它帮助了我,但我认为这是比这里解释的例子更复杂的一个层次。希望得到社区的帮助。

这是我的views表,它存储广告在一天中的观看次数的计数器。

+-------------+--------------+ 
| COLUMN_NAME | COLUMN_TYPE | 
+-------------+--------------+ 
| ad_day_id | bigint(13) | 
| advert_id | bigint(20) | 
| date  | date   | 
| views  | mediumint(6) | 
+-------------+--------------+ 

这是我的clicks表,它存储每个单独的点击。 (某些列排除在外,因为他们不相关的问题)

+-------------+---------------------+ 
| COLUMN_NAME | COLUMN_TYPE   | 
+-------------+---------------------+ 
| id   | bigint(20) unsigned | 
| advert_id | bigint(20)   | 
| timestamp | timestamp   | 
+-------------+---------------------+ 

结果应该像(使用,只是为了显示格式没有实数):

+------------+-------+--------+ 
| event_date | views | clicks | 
+------------+-------+--------+ 
| 2016-05-09 | 25 |  4 | 
| 2016-05-10 |  2 |  | 
| 2016-05-11 | 105 |  10 | 
| 2016-05-13 | 96 |  7 | 
| 2016-05-14 |  |  1 | 
+------------+-------+--------+ 

至于结果:

  • 不是每个日期都会有点击或浏览
  • 有些日期可能有意见,不点击
  • 有些日期可能有点击和没有意见

关的代码......这就是我目前有:

SELECT 
    $views_table.date AS event_date, 
    $views_table.views, 
    '' AS clicks 
FROM 
    $views_table 
WHERE 
    ($views_table.date BETWEEN '$from_date' AND '$to_date') 
    AND $views_table.advert_id=$advert_id 
UNION 
SELECT 
    CAST($clicks_table.timestamp AS DATE) AS event_date, 
    '' AS views, 
    COUNT($clicks_table.advert_id) AS clicks 
FROM 
    $clicks_table 
WHERE 
    (CAST($clicks_table.timestamp AS DATE) BETWEEN '$from_date' AND '$to_date') 
    AND $clicks_table.advert_id=$advert_id 
GROUP BY 
    event_date 
ORDER BY 
    event_date ASC; 

的一些注意事项上的代码:

  • 这些点击单独存储在时间戳上,因此必须是 转换日期,然后按日期分组(或者至少这是我得到 有效结果的方式为不同的报告)。
  • 该报告将以日期范围为特色,并针对特定广告。这是解释where子句。

在撰写此问题时,我将代码格式化得更好一些,而且为了便于阅读,我更改了解决最初问题的select语句的顺序。显然,两个选择都必须具有相同的列并且具有相同的顺序。

我觉得我几乎没有,因为这是我目前的结果是:

+------------+-------+--------+ 
| event_date | views | clicks | 
+------------+-------+--------+ 
| 2016-05-09 | 1  |  | 
| 2016-05-09 |  | 1  | 
| 2016-05-10 | 2  |  | 
| 2016-05-11 | 105 |  | 
| 2016-05-11 |  | 7  | 
| 2016-05-13 | 96 |  | 
| 2016-05-13 |  | 16  | 
| 2016-05-14 | 2  |  | 
| 2016-05-14 |  | 1  | 
| 2016-05-15 | 2  |  | 
| 2016-05-15 |  | 2  | 
+------------+-------+--------+ 

我剩下的问题是重复的日期。我该如何解决这个问题?
非常感谢那些善意回答的人!

+0

“我想我快到了” - 你是。把你的代码放在子查询中,并使用'GROUP BY event_date'。您将需要调整SELECT。 –

回答

1

我修改您的查询一点点(见在线评论),并把它包在一个子查询在外部查询使用GROUP BY event_date

SELECT event_date, MAX(views) AS views, MAX(clicks) AS clicks 
FROM (
    SELECT 
     views.date AS event_date, 
     views.views, 
     0 AS clicks -- '' causes strange results on sqlfiddle 
    FROM 
     views 
    WHERE 
     (views.date BETWEEN '2016-05-09' AND '2016-05-15') 
     AND views.advert_id=1 
    UNION 
    SELECT 
     CAST(clicks.timestamp AS DATE) AS event_date, 
     0 AS views, -- '' causes strange results on sqlfiddle 
     COUNT(clicks.advert_id) AS clicks 
    FROM 
     clicks 
    WHERE 
     (CAST(clicks.timestamp AS DATE) BETWEEN '2016-05-09' AND '2016-05-15') 
     AND clicks.advert_id=1 
    GROUP BY 
     event_date 
    -- ORDER BY is useless here 
) sub 
GROUP BY event_date 
ORDER BY event_date 

Demo

相反的CAST(clicks.timestamp AS DATE)你也可以使用DATE(clicks.timestamp)并希望MySQL将在未来使用索引。

+0

非常感谢保罗,这就像一个魅力,我用我的代码中的所有建议去。 DATE()命令正常工作。呜呼,很开心! – FreshSnow

1

这不是一个你需要的简单联合,而是一个联合和连接。因此,您需要一个工会才能从视图和点击表中获取日期的组合列表。然后,你需要离开加入viewes和点击日期的名单表:

select ds.event_date, max(v.views) views, count(c.clicks) clicks 
from 
    (select distinct date as event_date from views 
    union distinct 
    select distinct date(timestamp) from clicks) ds 
left join views v on ds.event_date=v.date 
left join clicks c on ds.event_date=date(c.timestamp) 
where ... 
group by ds.event_date 
+0

你需要通过'advert_id'过滤你的子查询。和(我不知道,但)不会'联合不同'使'选择不同'冗余? –

+0

@PaulSpiegel我也不确定,因此我保留了选择的区别。在第一个查询中可能是多余的。 – Shadow

+0

[文档](http://dev.mysql.com/doc/refman/5.7/en/union.html)不是很精确:“重复的行从结果中删除”。但我已经在[sqlfiddle](http://sqlfiddle.com/#!9/adbd9/7)上测试过。但是,如果'views.date'已经不是很明显,那么由于双重连接,您将得到错误的点击计数。但是,这是OPs问题:-) –

相关问题