Как мне GROUP BY на каждом заданном приращении значения поля? - PullRequest
1 голос
/ 13 мая 2009

У меня есть приложение на Python. Он имеет базу данных SQLite, полную данных о происходящих событиях, полученных веб-шабером из Интернета. Эти данные включают группы даты-времени, такие как метки времени Unix, в зарезервированном для них столбце. Я хочу получить названия организаций, которые что-то делали, и посчитать, как часто они это делали, но делать это каждую неделю (то есть 604 800 секунд), для которых у меня есть данные.

псевдокод:

for each 604800-second increment in time:
 select count(time), org from table group by org

По сути, я пытаюсь выполнить итерацию по базе данных, как список, отсортированный по столбцу времени, со значением шага 604800. Цель состоит в том, чтобы проанализировать, как распределение различных организаций в целом менялось с течением времени.

Если это вообще возможно, я бы не хотел извлекать все строки из БД и обрабатывать их в Python, поскольку это кажется а) неэффективным и б), вероятно, бессмысленным, учитывая, что данные находятся в базе данных.

Ответы [ 3 ]

1 голос
/ 13 мая 2009

Чтобы сделать это на основе множеств (что хорошо для SQL), вам понадобится основанное на множествах представление ваших приращений времени. Это может быть временная таблица, постоянная таблица или производная таблица (то есть подзапрос). Я не слишком знаком с SQLite, и прошло много времени с тех пор, как я работал с UNIX. Временные метки в UNIX - всего # секунды с момента установки даты / времени? Использование стандартной таблицы Календаря (которую полезно иметь в базе данных) ...

SELECT
     C1.start_time,
     C2.end_time,
     T.org,
     COUNT(time)
FROM
     Calendar C1
INNER JOIN Calendar C2 ON
     C2.start_time = DATEADD(dy, 6, C1.start_time)
INNER JOIN My_Table T ON
     T.time BETWEEN C1.start_time AND C2.end_time  -- You'll need to convert to timestamp here
WHERE
     DATEPART(dw, C1.start_time) = 1 AND    -- Basically, only get dates that are a Sunday or whatever other day starts your intervals
     C1.start_time BETWEEN @start_range_date AND @end_range_date  -- Period for which you're running the report
GROUP BY
     C1.start_time,
     C2.end_time,
     T.org

Таблица календаря может принимать любую форму, которую вы хотите, так что вы можете использовать метки времени UNIX в ней для start_time и end_time. Вы просто предварительно заполняете его всеми датами в любом возможном диапазоне, который вы можете использовать. Даже переход с 1900-01-01 на 9999-12-31 не будет ужасно большим столом. Это может пригодиться для большого количества запросов типа отчетов.

Наконец, этот код - T-SQL, поэтому вам, вероятно, потребуется преобразовать DATEPART и DATEADD во все, что эквивалентно SQLite.

1 голос
/ 14 мая 2009

Не знаком с SQLite. Я думаю, что этот подход должен работать для большинства баз данных, так как он находит номер недели и вычитает смещение

SELECT org, ROUND(time/604800) - week_offset, COUNT(*)
FROM table
GROUP BY org, ROUND(time/604800) - week_offset

В Oracle я бы использовал следующее, если бы время было столбцом даты:

SELECT org, TO_CHAR(time, 'YYYY-IW'), COUNT(*)
FROM table
GROUP BY org, TO_CHAR(time, 'YYYY-IW')

SQLite, вероятно, имеет аналогичную функциональность, которая позволяет использовать этот тип SELECT, что проще для глаз.

1 голос
/ 13 мая 2009

Создайте таблицу со списком всех недель с начала эпохи и JOIN добавьте ее в свою таблицу событий.

CREATE TABLE Weeks (
  week INTEGER PRIMARY KEY
);

INSERT INTO Weeks (week) VALUES (200919); -- e.g. this week

SELECT w.week, e.org, COUNT(*)
FROM Events e JOIN Weeks w ON (w.week = strftime('%Y%W', e.time))
GROUP BY w.week, e.org;

Есть только 52-53 недели в год. Даже если вы заполняете таблицу Weeks в течение 100 лет, это все еще маленький столик.

...