sql >> Databasteknik >  >> RDS >> Mysql

Fylla i luckor i datum som returneras från databasen - ren SQL-lösning möjlig?

Ja, det är bättre att skapa en siffertabell (enkel kolumn N) som inte innehåller annat än siffrorna 0 till 999. Den kan användas till många saker, inte minst en fråga som nedan:

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

Du använder fel format. Det är VERSALT W, inte lägre för veckodagen, så '%W %M %Y' eller '%d %M %Y' för dagen i månaden.http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

Du använder GROUP BY DAY(FROM_UNIXTIME(click_date)) notera "dag" inte veckodag, men du visar (eller försöker) "%W" (vardag) - välj en, blanda inte dem.

EDIT: Om du föredrar att inte materialisera (skapa som en riktig tabell) en siffersekvenstabell, kan du konstruera en i farten. Det blir inte snyggt.

Notera:N1, N2 och N3 nedan kombineras för att ge ett möjligt intervall på 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

EDIT #2: En rak datumtabell

Lägg detta i ett nytt fönster i phpMyAdmin eller kör det som en batch. Den skapar en tabell med namnet Datum, med varje enskilt datum från dag 1900-01-01 (eller ändra i skriptet) till 2300-01-01 (eller ändra).

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;

Med en sådan verktygstabell kan din fråga bara vara

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


  1. Snabbt inlägg om SQLite UPSERT och den nya RETURNING-satsen.

  2. Felsökning av SQL Server Always On Availability Groups

  3. Hur skapar man en global konfigurationsfil?

  4. Hur lägger man till ett specifikt antal tomma rader i sqlite?