Заполнение пробелов в датах, возвращаемых из базы данных - возможно ли чисто SQL-решение? - PullRequest
2 голосов
/ 20 февраля 2011

У меня есть этот запрос:

SELECT COUNT(*) as clicks, DATE_FORMAT(FROM_UNIXTIME(click_date), '%w %M %Y') as point 
FROM tracking 
WHERE click_date < $end_date AND click_date > $start_date 
GROUP BY DAY(FROM_UNIXTIME(click_date))

Где $start_date - две недели назад, а $end_date - сегодняшняя дата.

Я пытаюсь найти все клики, сделанные каждый день законкретный диапазон дат.Я также хочу включить дни, когда не было кликов.Поскольку, естественно, в моей базе данных нет записи для них, мне нужно кое-что включить, как, как мне лучше всего это сделать, показывая все даты от начальной до конечной даты.Это то, что у меня сейчас есть, много пробелов в этом двухнедельном диапазоне дат.

Array
(
    [0] => Array
        (
            [clicks] => 17
            [point] => 0 February 2011
        )

    [1] => Array
        (
            [clicks] => 3
            [point] => 1 February 2011
        )

    [2] => Array
        (
            [clicks] => 14
            [point] => 5 February 2011
        )

    [3] => Array
        (
            [clicks] => 1
            [point] => 1 February 2011
        )

    [4] => Array
        (
            [clicks] => 8
            [point] => 2 February 2011
        )

)

Может ли это быть сделано с помощью чисто SQL-запроса или мне нужно использовать некоторую php-логику?

Кстати, почему у меня 0 February 2011 в качестве моего первого свидания!Хм, у меня тоже, кажется, есть повторяющиеся даты, которых не должно быть, может быть, мой GROUP BY работает неправильно?

Спасибо всем за помощь.

Ответы [ 3 ]

5 голосов
/ 20 февраля 2011

Можно ли это сделать с помощью чисто SQL-запроса или мне нужно использовать некоторую php-логику?

Да, лучше создать таблицу чисел (один столбец N), которая не содержит ничего, кроме чисел от 0 до 999. Она может использоваться для многих вещей, не в последнюю очередь для запроса, подобного приведенному ниже:

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

Кстати, почему у меня 0 февраля 2011 года в качестве моего первого свидания

Вы используете неправильный формат. ВЕРХНИЙ случай W не ниже для дня недели, поэтому '% W% M% Y' или '% d% M% Y' для дня месяца. http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

может быть, моя GROUP BY не работает правильно?

Вы используете GROUP BY DAY(FROM_UNIXTIME(click_date)) note "день" не день недели, но вы отображаете (или пытаетесь) "% W" (день недели) - выберите один, не делайте смешивать их.


РЕДАКТИРОВАТЬ: Если вы предпочитаете не материализовать (создать в качестве реальной таблицы) таблицу последовательности чисел, вы можете создать ее на лету. Это не будет красиво.

Примечание: N1, N2 и N3 ниже объединяются, чтобы дать возможный диапазон 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

РЕДАКТИРОВАНИЕ № 2: Таблица прямых дат

Поместите это в новое окно в phpMyAdmin или запустите как пакет. Он создает таблицу с именем Dates, с каждой отдельной датой от дня 1900-01-01 (или изменения в сценарии) до 2300-01-01 (или изменения).

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;

С такой таблицей утилит ваш запрос может быть просто

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
0 голосов
/ 20 февраля 2011

Я бы придерживался логики PHP, зацикливаясь между самой низкой датой и самой высокой датой, и увеличивая один день за раз.

Скорее всего, вы могли бы сделать это в SQL с помощью некоторых необычных соединений, но я даже не стану рассматривать эту злобность!

Кстати, %w - это день недели , начиная с 0 = воскресенье. Вы, вероятно, хотели %d.

0 голосов
/ 20 февраля 2011

По моему мнению, вам лучше использовать логику такого типа в вашем коде. Но если вы хотите сделать это в чистом SQL, вы можете сконструировать запрос, который даст вам результаты всех дней между одним днем ​​и следующим ... либо вставив во временную таблицу, либо в таблицу в памяти ... затем оставьте включите это в свои результаты, чтобы получить все дни независимо от того, были ли результаты за этот день.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...