Advanced Reports dient der Anzeige aufgelaufener Daten.
Als Datenquelle sind zwei Arten möglich:
Beide haben ihre Berechtigung
Sind die abzufragenden Tabellen klein, die Aktualität wichtig und sich die zugrundeliegenden Daten oft ändern, so ist die erste Variante Favorit
Sind die abzufragenden Tabellen groß, die Aktualität nicht so wichtig und die zugrundeliegenden Daten sich nur selten ändern, so ist die zweite Variante besser
Oft muss man reportspezifisch entscheiden, welche Art gewählt werden soll
Das kann man den Benutzer in Views-UI entscheiden lassen, mit Vorbelegung nach einem Eintrag vom zuständigen ReportModul
Der schnelle Zugriff auf zwischengespeicherte Daten ist nicht umsonst:
Es gibt verschiedene Arten von Reports mit aufgelaufenen Daten
Zeitabhängige Daten mit einer Zeitachse (siehe ScenarioZ)
In der Tabelle eine Zeile pro Zeiteinheit (Tag, Monat, …)
Im Chart mit x-Achse == Zeitachse
Für zeitabhängige Daten bietet es sich an, ein Navigationssystem anzubieten, das ein schnelles und flexibles Navigieren ermöglicht (einmalig programmiet in adv_reports, möglicherweise mit Optionen in Views-UI)
Zeitunabhängig, nach Gruppenfeldern (siehe ScenarioG)
In der Tabelle eine Zeile pro Gruppe (Boston, Caligiari, London, …)
Im Chart mit x-Achse == Gruppenachse
Diese zweite Art kann getrost zurückgestellt werden, adv_reports sollte aber eine Erweiterung in diese Richtung nicht blockieren
Details zu zeitabhängigen Daten: Für Life-Abfragen müssen nur die Abfragen richtig ausgeführt werden, für die Zwischenspeicherung ist die Frage, wie die Daten in der Tabelle adv_reports abgelegt werden.
Anforderungen:
Der Anwender muss ein Report erstellen können mit einem selbst gewählten Zeitabschnitt (VonDatum, BisDatum)
Ebenso für vordefinierte Zeitabschnitte (Monat: 2012-4, Jahr: 2012, …)
Alle Zeitabschnitte lassen sich mit VonDatum/BisDatum ausdrücken,
doch die Zeiteinheit für das Jahr sollte Monat sein und nicht Tag, vielleicht auch Kalenderwoche, wobei es allerdings ein Randproblem gibt.
Tabellenstruktur:
rid(varchar 255, primary key), dummy(int), data(longblob)
rid ist strukturiert (module/report/delta)
module: Daten gehören einem Report des Moduls an
aufgrund des Feldes weiss adv_reports, welches Modul es befragen muss
report: Name des Reports
delta: Gibt den Zeitraum an, für den im Feld data die Nutzdaten abgelegt sind
Für zeitabhängige Daten gibt es genau 2 Arten von Datensätzen: Monat und Jahr,
für zeitunabhängige Daten wird es wohl nicht benötigt, ich vermute, dass dort alles etwas einfacher ist
Monat: format='YYYY-MM', data enthält Daten für den Monat mit der Zeiteinheit Tag (also die aufgelaufenen Summen pro Tag)
Jahr: format='YYYY', data enthält Daten für das Jahr mit der Zeiteinheit Monat (also die aufgelaufenen Summen pro Monat)
Vielleicht ist es wegen Views-UI günstiger das Feld rid aufzuspalten
etwa in rid(autoincrement), module(varchar64), report(varchar32), delta(varchar16),
muss ausprobiert werden
dummy: Vermutlich bedarf es eines int-Feldes für exposed form (Views-UI),
immer 0 in der Tabelle, im Filter (Views-UI) immer == 0 (also keine Filterung)
data: Enthält die Nutzdaten (aufgelaufene Summen pro Zeiteinheit), serialisiert
Assoziatives Array mit
Key=Datum(format='YYYY-MM-DD') und einem Array in Value mit einem Array in jedem Item, das die Daten für jede angebotene Spalte der Zieltabelle enthält,
bzw. mit Key=Monat(format='YYYY-MM') für Jahresdaten
Zugriff auf die Tabelle
Zuerst der einfachere Fall: Verlangt ist der Report für einen Monat (bzw. Jahr), etwa 2012-04 (bzw. 2012)
Möglicherweise ist ein Datensatz für den Monat (Jahr) in der Tabelle vorhanden und das View liefert im $view→result (adv_reports_views_pre_render) bereits diesen Datensatz, dann müssen die Daten nur noch für den Renderer umgeformt werden,
ist der Satz nicht vorhanden,
dann wird das betroffene Modul gebeten, die benötigten Daten zu liefern (die benötigten Infos sind im Feld rid)
die Daten werden in die Tabelle adv_reports eingetragen
und zuletzt eben für den Renderer umgeformt
Verlangt ist der Report für einen beliebigen Zeitabschnitt (VonDatum, BisDatum)
Der AnfrageZeitraum steht im View.Filter (bzw. ajax.date_filter) als Entsprechung für das Feld delta, alledings in einem Format, zu dem es niemals einen Datensatz gibt,
also muss das Modul adv_reports etwas mehr tun:
es liest die Datensätze der betroffenen Monate
und füllt daraus ein Array mit den Daten aller Tage im Zeitraum ('Monate' haben bereits die Daten nach Einzeltagen)
für Monate, da noch keine Daten in der Tabelle vorhanden sind, da wird wie oben vorgegangen, Daten erstellen lassen und diese in die Tabelle schreiben
Beispiel: Report für den Zeitraum von=2012-1-24 bis=2012-5-17
Gelesen werden die Daten der Monate Januar, Februar, März, April und Mai (wenn Daten eines Monats nicht vorhanden, dann wie oben)
In unser ZielArray werden die Daten aller Tage von Februar, März und April übertragen,
vom Januar die letzten 8 Tage (24.1 - 31.1)
und vom Mai die ersten 17 Tage
Danach wie gewohnt die Umformung für den Renderer
Inwieweit es Sinn macht, einen Zeitraum, der sich über Jahre erstreckt, noch mit der Zeiteinheit 'Tag' auszugeben, sei erst einmal dahingestellt.
Aktualisierung bei Tabellenänderungen
Zugrundeliegende Tabellen für unsere Reports ändern sich, Datensätze werden hinzugefügt oder gelöscht, oder es werden bestehende Daten geändert. Damit unsere Reports die richtigen Zahlen liefern, müssen wir auf jede Änderung reagieren, sofern es diese Reports betrifft
Dazu müssen wir von jedem Module wissen, welche Tabellen sie für ihre Reports auswerten, um gezielt reagieren zu können
Es gibt dann zwei Möglichkeiten zu reagieren
(die einfachere) Die betroffenen Datensätze unserer Tabelle adv_reports löschen (bzw. deren Inhalt), damit bei nächster ReportErstellung die Summen neu gerechnet werden müssen
Wo das zeitkritisch ist, oder überhaupt, da könnte man bei den betroffenen Datensätzen für die betroffene Zeiteinheit die aufgelaufenen Summen geziel korrigieren, also Datensatz lesen, Zeiteinheit suchen, Summen korrigieren und den Datensatz zurückschreiben (mag sein, dass das nicht ganz trivial ist)