2

我正在尝试为一个广告的效果汇总一份报告,显示它在一天内的浏览量和点击量。视图和点击存储在具有不同结构的单独表中,所以我认为我必须执行联合。

我已经阅读并理解了这篇精彩的文章。它对我有所帮助,但我认为这比那里解释的示例要复杂一个级别。希望得到社区的一些帮助。

这是我的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 子句。

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

我想我快到了,因为这是我目前的结果:

+------------+-------+--------+
| 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      |
+------------+-------+--------+

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

4

2 回答 2

1

它不是你需要的简单联合,而是联合和连接。因此,您需要一个联合来从视图和点击表中获取日期的组合列表。然后你需要在日期列表中左加入视图和点击表:

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
于 2016-05-15T10:41:23.813 回答
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

演示

代替CAST(clicks.timestamp AS DATE)你也可以使用DATE(clicks.timestamp)并希望 MySQL 将来会使用索引。

于 2016-05-15T14:23:29.300 回答