Wie kann ich GROUP BY auf jedem gegebenen Inkrement eines Feldwert?
Frage
Ich habe eine Python-Anwendung. Es hat eine SQLite-Datenbank, voll von Daten über Dinge, die, abgerufen von einem Web-Schaber aus dem Web passieren. Diese Daten umfassen Zeit-date Gruppen, wie Unix-Zeitstempel, in einer Spalte für sie reserviert. Ich möchte die Namen von Organisationen abzurufen, die Dinge taten und zählen, wie oft sie sie taten, aber dies für jede Woche zu tun (das heißt 604.800 Sekunden) Ich habe Daten für.
Pseudocode:
for each 604800-second increment in time:
select count(time), org from table group by org
Im Wesentlichen ist zu tun, was ich versuche, wie eine Liste auf der Zeitspalte, mit einem Schrittwert von 604800. Das Ziel sortierte durch die Datenbank laufen ist zu analysieren, wie die Verteilung der verschiedenen Organisationen in den gesamten im Laufe der Zeit verändert.
Wenn möglich, möchte ich alle Zeilen aus der DB zu vermeiden, ziehen und deren Verarbeitung in Python, da dies scheint a) ineffizient und b) wahrscheinlich sinnlos gegeben, dass die Daten in einer Datenbank ist.
Lösung
Nicht mit SQLite vertraut zu sein denke ich, dieser Ansatz sollte für die meisten Datenbanken arbeiten, da sie die Wochennummer findet und subtrahiert den Offset
SELECT org, ROUND(time/604800) - week_offset, COUNT(*)
FROM table
GROUP BY org, ROUND(time/604800) - week_offset
In Oracle würde ich folgende verwenden, wenn Zeit eine Datumsspalte ist:
SELECT org, TO_CHAR(time, 'YYYY-IW'), COUNT(*)
FROM table
GROUP BY org, TO_CHAR(time, 'YYYY-IW')
SQLite hat wahrscheinlich eine ähnliche Funktionalität, die diese Art von SELECT ermöglicht, die einfacher auf dem Auge ist.
Andere Tipps
Erstellen Sie eine Tabelle, alle Wochen seit Beginn der Epoche und JOIN
es der Ereignisse auf den Tisch.
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;
Es gibt nur 52-53 Wochen pro Jahr. Selbst wenn Sie die Wochen-Tabelle für 100 Jahre füllen, das ist immer noch ein kleiner Tisch.
Um dies zu tun, in einem Satz basiert (was SQL ist gut) Sie eine Set-basierte Darstellung Ihrer Zeitschritte benötigen. Das kann eine temporäre Tabelle, eine permanente Tabelle oder einer abgeleiteten Tabelle (d.h. Unterabfrage) sein. Ich bin nicht allzu vertraut mit SQLite und es ist schon eine Weile her, seit ich mit UNIX gearbeitet habe. Zeitstempel in UNIX sind nur # Sekunden seit einiger eingestellte Datum / Zeit? Mit einer Standard-Kalender-Tabelle (was nützlich ist, in einer Datenbank zu haben) ...
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
Die Kalender-Tabelle kann nehmen, was Form Sie wollen, so dass Sie UNIX-Zeitstempel in der es für die Startzeit und end_time nutzen könnten. Sie haben soeben vorge füllen Sie es mit all den Terminen in jedem denkbaren Bereich, den Sie verwenden möchten. geht sogar von 1900-01-01 bis 9999-12-31 wird eine schrecklich große Tabelle nicht sein. Es kann für viele nützlich sein, vom Typ Abfrage berichten.
Schließlich ist dieser Code T-SQL, so werden Sie wahrscheinlich den Datepart und DATEADD konvertieren müssen, was auch immer die äquivalent ist in SQLite.