Mysql
 sql >> Database >  >> RDS >> Mysql

MySQL raggruppa per data e conteggio comprese le date mancanti

Hai bisogno di un OUTER JOIN arrivare a tutti i giorni tra un inizio e una fine perché se utilizzi un INNER JOIN limiterà l'output solo alle date che sono unite (cioè solo quelle date nella tabella del rapporto).

Inoltre, quando utilizzi un OUTER JOIN devi fare attenzione a queste condizioni nella where clause non causare un implicit inner join; ad esempio AND domain_id =1 se l'uso nella clausola where sopprime qualsiasi riga per cui non è stata soddisfatta tale condizione, ma quando viene utilizzata come condizione di join limita solo le righe della tabella del report.

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;

Ho anche cambiato la tabella derivata all_dates, usando DATE_ADD() per spingere il punto di partenza nel futuro, e ho ridotto le sue dimensioni. Entrambe sono opzioni e possono essere modificate come meglio credi.

Demo su SQLfiddle

per arrivare a un domain_id per ogni riga (come mostrato nella tua domanda) dovresti usare qualcosa come il seguente; Nota che potresti usare IFNULL() che è specifico per MySQL ma ho usato COALESCE() che è SQL più generico. Tuttavia, l'uso di un parametro @ come mostrato qui è comunque specifico per MySQL.

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;

Vedi questo su SQLfiddle