#sql #postgresql
#sql #postgresql
Вопрос:
Мне нужно выполнить некоторый статистический анализ интервалов, т.Е. Разницы между двумя полями даты и времени в таблице.
Согласно документации aggregate function здесь. Агрегатные функции для MAX
, MIN
, AVG
и т. Д., т. Е. Общие агрегатные функции, Принимают аргументы для полей даты, времени и интервала.
Однако для более продвинутых статистических функций, таких как stddev_pop
, var_pop
, var_sam
и std_samp
поддерживаемые входные данные, по-видимому, являются только числовыми или аналогичными. Хотя в документации предполагается, что между двумя типами функций нет разницы
… (Они выделены просто для того, чтобы не загромождать список наиболее часто используемых агрегатов.)…
Есть ли какой-нибудь простой способ вычислить эти параметры? и почему тип интервала в качестве аргумента не поддерживается? Эти типы статистических агрегированных функций инвариантны к единицам измерения?
PS Я не уверен, что смогу извлечь эпоху и использовать ее, поскольку некоторые значения могут быть отрицательными.
Комментарии:
1. Разница между двумя полями даты и времени кажется мне числовой.
2. Это то, о чем я тоже подумал, однако разница заключается в интервале типа даты, и эти функции не принимают интервальные входные данные, хотя avg делает это, что для меня не имеет никакого смысла.
3. @DanBracuk разница между ними
timestamps
заключается вinterval
4. Я не уверен, что смогу извлечь эпоху и использовать ее, поскольку некоторые значения могут быть отрицательными. В чем проблема с отрицательными значениями? Если они вам не нужны, почему вы не можете получить абсолютное значение?
5. Ну, я не уверен, как они работают для интервалов postgresql. Я знаю, что для абсолютной отметки времени это разница между эпохой Unix и заданным временем. Но
interval
уже ли относительное время между двумя датами, как вы можете «извлечь» эпоху или вычислить разницу между тем, что уже является разницей? . Если мне придется применять это непосредственно к полям временных меток, придется ли мне также учитывать отрицательные периоды времени для дат до 1970 года?
Ответ №1:
Как я уже сказал в комментарии, чтобы вручную определить стандартное отклонение выборки, в какой-то момент вы умножаете интервал на интервал. PostgreSQL этого не поддерживает.
Чтобы обойти эту проблему, уменьшите интервал до часов, минут или секунд (или чего угодно). Это оказывается намного проще, чем выполнять вычисления вручную, и это говорит о том, почему PostgreSQL не поддерживает такого рода вычисления из коробки.
Во-первых, функция из общего списка рассылки PostgreSQL
CREATE OR REPLACE FUNCTION interval_to_seconds(interval)
RETURNS double precision AS $$
SELECT (extract(days from $1) * 86400)
(extract(hours from $1) * 3600)
(extract(minutes from $1) * 60)
extract(seconds from $1);
$$ LANGUAGE SQL;
Теперь мы можем взять стандартное отклонение простого набора интервалов.
with intervals (i) as (
values (interval '1 hour'), (interval '2 hour'), (interval '3 hour'),
(interval '4 hour'), (interval '5 hour')
)
, intervals_as_seconds as (
select interval_to_seconds(i) as seconds
from intervals
)
select stddev(seconds), stddev(seconds)/60
from intervals_as_seconds
in_sec in_min двойная точность двойная точность -- 5692.09978830308 94.8683298050514
Вы можете проверить результаты, как вам нравится.
Теперь предположим, что вам нужна часовая детализация вместо секунд. Очевидно, что выбор степени детализации сильно зависит от приложения. Вы можете определить другую функцию, interval_to_hours(interval)
. Вы можете использовать очень похожий запрос для вычисления стандартного отклонения.
with intervals (i) as (
values (interval '1 hour'), (interval '2 hour'), (interval '3 hour'),
(interval '4 hour'), (interval '5 hour')
)
, intervals_as_hours as (
select interval_to_hours(i) as hours
from intervals
)
select stddev(hours) as stddev_in_hrs
from intervals_as_hours
stddev_in_hr двойная точность -- 1.58113883008419
Значение стандартного отклонения в часах явно отличается от значения в минутах или секундах. Но они измеряют одно и то же. Дело в том, что «правильный» ответ зависит от степени детализации (единиц измерения), которую вы хотите использовать, и есть много вариантов. (Я полагаю, от микросекунд до столетий.)
Также рассмотрите это утверждение.
select interval_to_hours(interval '45 minutes')
интервал_to_hours двойная точность -- 0
Это правильный ответ? Вы не можете сказать; правильный ответ зависит от приложения. Я могу представить приложения, которые хотели бы, чтобы 45 минут рассматривались как 1 час. Я также могу представить приложения, которые хотели бы, чтобы 45 минут рассматривались как 1 час для некоторых вычислений и как 0 часов для других вычислений.
И подумайте об этом вопросе. Сколько секунд в месяце? Выражение select interval '1' month;
допустимо; количество секунд зависит от того, сколько дней в месяце.
И я думаю, именно поэтому PostgreSQL не поддерживает такого рода вычисления из коробки. Правильный способ сделать это с интервальными аргументами слишком зависит от приложения.
Позже . . .
Я нашел это обсуждение в одном из списков рассылки PostgreSQL.
Комментарии:
1. Нет необходимости писать свои собственные
interval_to_seconds()
. Это можно сделать с помощьюextract(epoch from ...)
2. спасибо за подробное объяснение. Поток списка рассылки появился в поиске Google, однако я не был уверен, почему тогда такой взлом казался необходимым. Разные единицы измерения изменяют значения, особенно потому, что время не соответствует стандартному десятичному преобразованию. Я думаю, что, предполагая, что значение по умолчанию, скажем, секунд, возможно, это может быть нежелательно или нецелесообразно.
3. Я не могу это проверить, но вы можете попытаться снова вычислить результат в секундах, я использую thison Teradata:
stddev(seconds) * interval '0000 00:00:00' second