sql >> Base de Datos >  >> RDS >> Mysql

MySQL agrupa por fecha y cuenta, incluidas las fechas que faltan

Necesitas una OUTER JOIN para llegar a todos los días entre un inicio y un final porque si usa un INNER JOIN restringirá la salida a solo las fechas que se unen (es decir, solo esas fechas en la tabla del informe).

Además, cuando usa un OUTER JOIN debe tener cuidado de que las condiciones en la cláusula where clause no provoque una implicit inner join; por ejemplo Y ID_dominio =1 si el uso en la cláusula where suprimiría cualquier fila que no cumpliera con esa condición, pero cuando se usa como una condición de combinación, solo restringe las filas de la tabla de informes.

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;

También he cambiado la tabla derivada all_dates, usando DATE_ADD() para empujar el punto de partida hacia el futuro, y he reducido su tamaño. Ambas son opciones y se pueden ajustar como mejor le parezca.

Demostración en SQLfiddle

para llegar a un domain_id para cada fila (como se muestra en su pregunta), necesitaría usar algo como lo siguiente; Tenga en cuenta que podría usar IFNULL() que es específico de MySQL pero he usado COALESCE() que es un SQL más genérico. Sin embargo, el uso de un @parámetro como se muestra aquí es específico de MySQL de todos modos.

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;

Vea esto en SQLfiddle