2009-08-15 2 views
2

У меня есть таблица с записями, которые выглядят так:SQL Query для подсчета записей, соответствующих дневному диапазону дат?

CREATE TABLE sample (
    ix int unsigned auto_increment primary key, 
    start_active datetime, 
    last_active datetime 
); 

Мне нужно знать, сколько записей были активны на каждом из последних 30 дней. Дни также должны быть отсортированы по возрастанию, чтобы они были возвращены от старых к новейшим.

Я использую MySQL и запрос будет запущен с PHP, но мне действительно не нужен код PHP, просто запрос.

Вот мой старт:

SELECT COUNT(1) cnt, DATE(?each of last 30 days?) adate 
FROM sample 
WHERE adate BETWEEN start_active AND last_active 
GROUP BY adate; 

ответ

5

Сделайте внешнее соединение.

Нет стола? Сделайте стол. Для этого я всегда держу стол для манекена.

create table artificial_range( 
    id int not null primary key auto_increment, 
    name varchar(20) null) ; 

-- or whatever your database requires for an auto increment column 

insert into artificial_range(name) values (null) 
-- create one row. 

insert into artificial_range(name) select name from artificial_range; 
-- you now have two rows 

insert into artificial_range(name) select name from artificial_range; 
-- you now have four rows 

insert into artificial_range(name) select name from artificial_range; 
-- you now have eight rows 

--etc. 

insert into artificial_range(name) select name from artificial_range; 
-- you now have 1024 rows, with ids 1-1024 

Теперь делают его удобным в использовании, и ограничить его до 30 дней, с целью:

Edit: JR Lawhorne отмечает:

Вы должны изменить "DATE_ADD" в " date_sub ", чтобы получить предыдущие 30 дней в созданном представлении.

Thanks JR!

create view each_of_the_last_30_days as 
select date_sub(now(), interval (id - 1) day) as adate 
from artificial_range where id < 32; 

Теперь используйте это в запросе (я на самом деле не проверял ваш запрос, я только предполагаю, что это работает правильно):

Edit: я должен присоединиться к другому способу:

SELECT COUNT(*) cnt, b.adate 
FROM each_of_the_last_30_days b 
left outer join sample a 
on (b.adate BETWEEN a.start_active AND a.last_active) 
GROUP BY b.adate; 
+0

Вам необходимо изменить «date_add» на «date_sub», чтобы получить предыдущие 30 дней в созданном представлении. –

0

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

CREATE TEMPORARY TABLE days_ago (d SMALLINT); 
INSERT INTO days_ago (d) VALUES 
    (0), (1), (2), ... (29), (30); 

Теперь вы можете сравнить дату, которая d дней назад в пролете между start_active и last_active каждой строки. Укажите количество совпадающих строк в группе за значение d, и у вас есть счет.

SELECT CURRENT_DATE - d DAYS, COUNT(*) cnt, 
FROM days_ago 
LEFT JOIN sample ON (CURRENT_DATE - d DAYS BETWEEN start_active AND last_active) 
GROUP BY d 
ORDER BY d DESC; -- oldest to newest 

Еще одно замечание: вы не можете использовать псевдонимы столбцов, определенные в списке выбора в выражениях, пока вы не дойдете до пункта GROUP BY. На самом деле, в стандартном SQL вы не можете использовать их до предложения ORDER BY, но MySQL поддерживает использование псевдонимов в статьях GROUP BY и HAVING.

0

Включите дату в метку времени Unix, который секунд, в запросе, а затем просто найти разницу быть < = количество секунд, в течение месяца.

Вы можете найти более подробную информацию здесь: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_unix-timestamp

Если вам нужна помощь с запросом, пожалуйста, дайте мне знать, но MySQL имеет хорошие функции для работы с DateTime.

[Изменить] С тех пор, как я был в замешательстве относительно реального вопроса, мне нужно закончить газон, но прежде, чем я забуду, я хочу записать это.

Чтобы получить подсчет числа в день, вы захотите, чтобы ваше предложение where было таким, как описано выше, чтобы ограничить последние 30 дней, но вам нужно будет группировать по дням, и поэтому выберите путем преобразования каждого запуска до дня месяца, а затем подсчитать их.

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

+0

Включите, какая дата в временную метку unix? 'CURRENT_DATE - INTERVAL 30 DAY',' start_active' или 'end_active'? Как это помогает группе OP подсчет активных записей * за каждый день * последних тридцати? – pilcrow

+0

Включите start_active и last_active в unix_timestamp, или, хотя я этого не пробовал, вы могли бы использовать subtime() для вычитания времени, а затем для преобразования, или на странице, предложенной выше, вы можете использовать что-то вроде этого: select ID от СООБЩЕНИЯ, где SENT_TIME <(CURDATE() - INTERVAL 5 DAY); Независимо от того, просто просмотрите функции времени, и вы должны быть в состоянии найти то, что будет работать лучше всего для вас. –

+0

@ Джеймс Блэк, ваша фраза ответов предполагает, что вы думаете, что OP хочет знать количество записей, перекрывающихся с временным окном 30 дней, - но это неправильный вопрос, он хочет вместо этого узнать количество перекрывающихся записей * каждый день * за последние 30 дней. (Да, арифметика даты проста в родных типах SQL или с использованием целых марок эпох.) Возможно, вы могли бы разместить код для иллюстрации вашего предложения? – pilcrow

Смежные вопросы