MySQL 两张表的联合,一张带有时间戳,一张带有日期
MySQL union on two tables, one with timestamp and one with date
我正在尝试汇总一个广告的效果报告,显示它在一天内的浏览量和点击量。观看次数和点击次数存储在具有不同结构的单独 table 中,因此我认为我必须执行合并。
我已阅读并理解this fantastic piece。它对我有帮助,但我认为这比那里解释的例子复杂一个层次。希望社区提供一些帮助。
这是我的 views
table,它存储了一个广告一天的浏览量计数器。
+-------------+--------------+
| COLUMN_NAME | COLUMN_TYPE |
+-------------+--------------+
| ad_day_id | bigint(13) |
| advert_id | bigint(20) |
| date | date |
| views | mediumint(6) |
+-------------+--------------+
这是我的 clicks
table,它单独存储每次点击。
(有些列因与问题无关而被省略)
+-------------+---------------------+
| 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 语句的顺序,这解决了我最初的问题。显然,两个 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 |
+------------+-------+--------+
我剩下的问题是重复的日期。我该如何解决这个问题?
非常感谢好心解答的朋友们!
您需要的不是简单的并集,而是并集和联接。因此,您需要一个联合来从视图和点击中获取日期的组合列表 table。然后您需要左加入视图并单击日期列表中的 tables:
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
我稍微修改了您的查询(请参阅内联注释)并将其包装在子查询中以在外部查询中使用 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
你也可以用DATE(clicks.timestamp)
代替CAST(clicks.timestamp AS DATE)
,希望MySQL以后使用索引
我正在尝试汇总一个广告的效果报告,显示它在一天内的浏览量和点击量。观看次数和点击次数存储在具有不同结构的单独 table 中,因此我认为我必须执行合并。
我已阅读并理解this fantastic piece。它对我有帮助,但我认为这比那里解释的例子复杂一个层次。希望社区提供一些帮助。
这是我的 views
table,它存储了一个广告一天的浏览量计数器。
+-------------+--------------+
| COLUMN_NAME | COLUMN_TYPE |
+-------------+--------------+
| ad_day_id | bigint(13) |
| advert_id | bigint(20) |
| date | date |
| views | mediumint(6) |
+-------------+--------------+
这是我的 clicks
table,它单独存储每次点击。
(有些列因与问题无关而被省略)
+-------------+---------------------+
| 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 语句的顺序,这解决了我最初的问题。显然,两个 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 |
+------------+-------+--------+
我剩下的问题是重复的日期。我该如何解决这个问题?
非常感谢好心解答的朋友们!
您需要的不是简单的并集,而是并集和联接。因此,您需要一个联合来从视图和点击中获取日期的组合列表 table。然后您需要左加入视图并单击日期列表中的 tables:
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
我稍微修改了您的查询(请参阅内联注释)并将其包装在子查询中以在外部查询中使用 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
你也可以用DATE(clicks.timestamp)
代替CAST(clicks.timestamp AS DATE)
,希望MySQL以后使用索引