Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Füllen von Lücken in Daten, die von der Datenbank zurückgegeben werden - reine SQL-Lösung möglich?

Ja, es ist besser, eine Zahlentabelle (einzelne Spalte N) zu erstellen, die nur die Zahlen 0 bis 999 enthält. Sie kann für viele Dinge verwendet werden, nicht zuletzt für eine Abfrage wie die folgende:

SELECT COUNT(t.click_date) as clicks,
    DATE_FORMAT(adddate($start_date, interval N day), '%d %M %Y') as point 
FROM Numbers
LEFT JOIN tracking t
    ON t.click_date >= adddate($start_date, interval N day)
    and t.click_date < adddate($start_date, interval (N+1) day)
WHERE N between 0 and datediff($start_date, $end_date)
GROUP BY N

Sie verwenden das falsche Format. Es ist ein GROSS geschriebenes W, nicht kleiner für den Wochentag, also '%W %M %Y' oder '%d %M %Y' für den Tag des Monats.http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

Sie verwenden GROUP BY DAY(FROM_UNIXTIME(click_date)) notieren Sie "Tag" kein Wochentag, aber Sie zeigen (oder versuchen es) "%W" (Wochentag) - wählen Sie eine aus, mischen Sie sie nicht.

BEARBEITEN: Wenn Sie es vorziehen, eine Numbers-Sequenztabelle nicht zu materialisieren (als echte Tabelle zu erstellen), können Sie eine on-the-fly erstellen. Es wird nicht schön sein.

Hinweis:N1, N2 und N3 unten ergeben zusammen einen möglichen Bereich von 0-999

SELECT COUNT(t.click_date) as clicks,
    DATE_FORMAT(adddate($start_date, interval N day), '%d %M %Y') as point 
FROM (
    select N1 * 100 + N2 * 10 + N3 as N
    from (
    select 0 N1 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) N1
    cross join (
    select 0 N2 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) N2
    cross join (
    select 0 N3 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) N3
    ) Numbers
LEFT JOIN tracking t
    ON t.click_date >= adddate($start_date, interval N day)
    and t.click_date < adddate($start_date, interval (N+1) day)
WHERE N between 0 and datediff($start_date, $end_date)
GROUP BY N

BEARBEITUNG Nr. 2: Eine reine Datumstabelle

Legen Sie dies in einem neuen Fenster in phpMyAdmin ab oder führen Sie es als Batch aus. Es erstellt eine Tabelle namens Dates mit jedem einzelnen Datum ab dem Tag 1900-01-01 (oder im Skript ändern) zu 2300-01-01 (oder ändern).

DROP PROCEDURE IF EXISTS FillDateTable;

delimiter //
CREATE PROCEDURE FillDateTable()
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
  drop table if exists datetable;
  create table datetable (thedate datetime primary key, isweekday smallint);

  SET @x := date('1900-01-01');
  REPEAT 
    insert into datetable (thedate, isweekday) SELECT @x, case when dayofweek(@x) in (1,7) then 0 else 1 end;
    SET @x := date_add(@x, interval 1 day);
    UNTIL @x > date('2300-01-01') END REPEAT;
END//
delimiter ;

CALL FillDateTable;

Mit einer solchen Hilfstabelle kann Ihre Abfrage einfach sein

SELECT COUNT(t.click_date) as clicks,
    DATE_FORMAT(thedate, '%d %M %Y') as point 
FROM Dates
LEFT JOIN tracking t
    ON t.click_date >= thedate
    and t.click_date < adddate(thedate, interval 1 day)
WHERE thedate between $start_date and $end_date
GROUP BY thedate