Ich möchte das Durchschnittsalter meiner Benutzer kennen und habe dazu Folgendes getan:
# SELECT avg(age(birthday)) FROM "user";
avg
------------------------------------------
33 years 10 mons 32 days 08:33:10.577946
Was bedeutet die Anzahl der Tage? Wie kann es über 31 Tage sein?
Ich habe 3746 Datensätze und bin in der UTC-Zeitzone.
PS: Ich benutze Postgres 9.5.3
postgresql
n1r3
quelle
quelle
justify_days()
(oderjustify_interval
) verwenden, um das Intervall zu "normalisieren"SELECT age(avg(birthday)) FROM "user";
das gleiche Ergebnis?avg(birthday)
gibt "Keine Funktion stimmt mit dem angegebenen Namen und den angegebenen Argumenttypen überein."Antworten:
age()
gibt Intervalle zurück. In SQL-92 ist "anInterval
eine nicht verankerte Richtungsdauer der Zeitlinie" [1]. Sie haben zwei Typen aufgrund unterschiedlicher Monatslängen im Gregorianischen Kalender (Jahr zu Monat und Tag zu Sekunde). Oracle gibt eine Fehlermeldung aus, wenn Sie versuchen, das zu tun, was Sie getan haben . Intervalle können positiv und negativ sein. Sie müssen verankert sein, um eine genaue Bedeutung zu habendate + interval = date2
. Wenn Sie Durchschnittswerte dieser Werte ermitteln, ist dies im Allgemeinen schlecht definiert. Wenn Sie sie auf Alterswerte prüfen, erhalten Sie möglicherweise immer noch unerwartete Ergebnisse (wie dies der Fall ist).Was bedeutet a
3 month 32 days
in Postgres? Nun, nur der Code kann es mit Sicherheit sagen (oder derjenige, der es geschrieben hat). Ich denke, es bedeutet "einen Monat vorrücken, dann 32 Tage". Man kann Tage nicht in Monate umwandeln oder umgekehrt.Wie kann es passieren, dort zu sein? Der Durchschnitt reagiert empfindlich auf Ausreißer. Wenn also tagelang ein ziemlich großer Wert vorhanden ist, hat dies einen Einfluss. Wie werden
null
Werte behandelt? Haben einige Benutzer Daten für die Zukunft angegeben oder unangemessene Werte angegeben? Gibt es eine implizite Konvertierung? Haben Postgres-Entwickler eine spezielle Durchschnittsfunktion für Intervalle erstellt?Für Ihr Problem empfehle ich die Verwendung (Entschuldigung, wenn dies nicht funktioniert, habe ich keine Datenbank zur Hand):
select avg(extract(epoch from now()) - extract(epoch from birthday)) from "user";
Dies funktioniert für Benutzer in einem angemessenen Alter. Wenn Sie jedoch Benutzer ab dem 18. Jahrhundert hatten, hängt die Antwort auch vom Standort ab, da der neue Kalender später in einigen Ländern übernommen wurde.
Lesen Sie das folgende Buch, um andere Macken mit Daten kennenzulernen.
[1] "Entwicklung zeitorientierter Datenbankanwendungen in SQL", Richard T. Snodgrass, Morgan-Kaufmann, 1999. Siehe seine Homepage , Seiten 30-32.
quelle
extract(epoch FROM age(birthdate));
klingt für mich besser.extract(epoch from '1 month')' the value is undefined. A one month delta can be 28, 29, 30 or 31 days. The semantics of
age (t) verwenden, wirdnow()-t
eine korrekte Konvertierung zugelassen, aber jeder andere Referenzwert ist möglicherweise falsch. Das Delta auf der Ebene von Unix-Zeitstempeln zu nehmen, ermöglicht eine korrekte Verallgemeinerung (natürlich ohne Berücksichtigung von Schaltsekunden) und ist daher eine korrekte Verwendung im Produktionscode.Die Funktion
AGE()
gibt eineninterval
[1] -Wert zurück.Wenn Sie nur die Jahre berechnen möchten, müssen Sie diese über die
age
Funktion extrahieren , z.Weitere Informationen finden Sie in der Dokumentation [2].
Verweise:
quelle