sql >> Databasteknik >  >> RDS >> Mysql

MySQL-gruppera efter datum och antal inklusive saknade datum

Du behöver en OUTER JOIN att komma fram till varje dag mellan start och slut eftersom om du använder en INNER JOIN det kommer att begränsa utdata till bara de datum som är sammanfogade (dvs. bara dessa datum i rapporttabellen).

Dessutom, när du använder en OUTER JOIN du måste se till att villkoren i where clause orsaka inte en implicit inner join; till exempel AND domain_id =1 om användning i where-satsen skulle undertrycka alla rader som inte hade det villkoret uppfyllt, men när det används som ett joinvillkor begränsar det bara raderna i rapporttabellen.

SELECT
      COUNT(r.domain_id)
    , all_dates.Date AS the_date
    , domain_id
FROM (
        SELECT DATE_ADD(curdate(), INTERVAL 2 MONTH) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
        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
      ) all_dates
      LEFT OUTER JOIN reports r
                  ON all_dates.Date = r.tracked_on
                        AND domain_id = 1
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
      the_date
ORDER BY
      the_date ASC;

Jag har också ändrat den härledda tabellen för alla_datum genom att använda DATE_ADD() för att driva utgångspunkten in i framtiden, och jag har minskat dess storlek. Båda dessa är alternativ och kan justeras som du vill.

Demo på SQLfiddle

för att komma fram till ett domän-id för varje rad (som visas i din fråga) måste du använda något i stil med följande; Observera att du kan använda IFNULL() som är MySQL-specifik men jag har använt COALESCE() vilket är mer generisk SQL. Men användningen av en @parameter som visas här är MySQL-specifik ändå.

SET @domain := 1;

SELECT
      COUNT(r.domain_id)
    , all_dates.Date AS the_date
    , coalesce(domain_id,@domain) AS domain_id
FROM (
        SELECT DATE_ADD(curdate(), INTERVAL 2 month) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
        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
      ) all_dates
      LEFT JOIN reports r
                  ON all_dates.Date = r.tracked_on
                        AND domain_id = @domain
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
      the_date
ORDER BY
      the_date ASC;

Se detta på SQLfiddle



  1. MAX() vs GREATEST() i MySQL:Vad är skillnaden?

  2. Vilket läge för MySQL WEEK() uppfyller ISO 8601

  3. SQL Server Databas Objects Statistik

  4. Varför returnerar password_verify falskt?