簡體   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