繁体   English   中英

如何在 MySQL 中使用 JOIN SQLs 选择没有数据的所有日期?

[英]How to select all dates without data using JOIN SQLs in MySQL?

我有 3 个表,分别是用户、站点和站点流量。 users 表包含用户的名称和有关用户的其他详细信息。 每个用户都有 1 个或多个站点,这些站点存储在站点表中。 现在每个站点都有自己的流量数据。

我想要完成的是为所有用户选择每个站点没有流量数据的所有日期。 这应该显示所有用户的名称、每个用户的 site_ids 以及没有这些站点中的每一个的数据的日期。

在此查询中,我能够获取仅针对 1 个特定用户没有数据的日期。 如何修改此查询以列出所有用户及其站点以及每个站点没有数据的日期。

这是我的查询:

SELECT b.dates_without_data
FROM (
    SELECT a.dates AS dates_without_data
    FROM (
        SELECT CURDATE() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as dates
        FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as a
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as b
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as c
    ) a
    WHERE a.dates >= DATE_SUB(DATE_SUB(NOW(),INTERVAL 1 DAY), INTERVAL 35 DAY)
) b
WHERE b.dates_without_data NOT IN (
    SELECT recorded_on 
    FROM site_traffic, sites, users
    WHERE site_traffic.site_id = sites.site_id
    AND sites.user_id = users.user_id
    AND users.user_id = 1
)
AND b.dates_without_data < DATE_SUB(NOW(),INTERVAL 1 DAY)
ORDER BY b.dates_without_data ASC

谢谢你们的帮助。

我会使用反连接模式。

首先,在生成的可能日期列表和所有站点之间进行交叉连接操作。 这为我们提供了每天每个站点的行。 然后继续连接到用户表。

诀窍是反连接。 我们获取所有站点和所有日期的集合,然后“匹配”到 site_traffic 中的行。 我们只想返回没有匹配的行。 我们可以使用外连接来做到这一点,然后在 WHERE 子句中添加一个条件,如果找到匹配则排除该行。 只留下没有匹配的行。

像这样的东西:

 SELECT s.site_id
      , u.user_id
      , d.dt       AS date_without_data
   FROM (

    SELECT DATE(NOW()) - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY AS dt
      FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as a
      CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as b
      CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) as c
    HAVING dt >= DATE(NOW()) + INTERVAL -1-35 DAY
       AND dt <  DATE(NOW()) + INTERVAL -1 DAY

        ) d
  CROSS
   JOIN site s
   JOIN users u
     ON u.user_id = s.user_id
  LEFT
  JOIN site_traffic t
    ON t.site_id      = s.site_id
    ON t.recorded_on >= d.dt
   AND t.recorded_on  < d.dt + INTERVAL 1 DAY
 WHERE t.site_id IS NULL

 ORDER BY s.site_id, u.user_id

诀窍在于 WHERE 子句中的条件。 该发现匹配的行的任何行site_traffic将有一个非NULL值site_id (连接条件中与site_id的相等比较保证了这一点。)因此,如果我们排除所有具有非 NULL 值的行,我们将剩下没有匹配的行。

(我假设recorded_on 是一个日期时间,所以我使用了范围比较……来匹配给定日期内recorded_on任何值。如果recorded_on实际上是一个date (没有时间),那么我们可以做一个更简单的相等比较。 )

us表中添加您需要的任何表达式到 SELECT 列表。

有些人认为内联视图d (生成“所有日期”的列表)看起来有点乱。 但我没问题。

如果 MySQL 提供了一个表值函数,或者其他一些用于生成一系列整数值的“更漂亮”的机制,那就太好了。

我会在视图查询本身中包含日期上的所有条件,在视图中完成它,而不必与外部查询混为一谈。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM