Найти max, min, avg, процентиль счета (*) на ммдд PostgreSQL - PullRequest
0 голосов
/ 19 мая 2018

Postgres версия 9.4.18, PostGIS версия 2.2.

Вот таблицы, с которыми я работаю (и вряд ли может внести существенные изменения в структуру таблицы):

Table ltg_data (охватывает период с 1988 по 2018 годы):

Column   |           Type           | Modifiers 
----------+--------------------------+-----------
intensity | integer                  | not null
time      | timestamp with time zone | not null
lon       | numeric(9,6)             | not null
lat       | numeric(8,6)             | not null
ltg_geom  | geometry(Point,4269)     | 
Indexes:
"ltg_data2_ltg_geom_idx" gist (ltg_geom)
"ltg_data2_time_idx" btree ("time")

Size of ltg_data (~800M rows):

ltg=# select pg_relation_size('ltg_data');
pg_relation_size 
------------------
149729288192

Округа таблиц:

 Column   |            Type             |                       Modifiers                      
-----------+-----------------------------+---------------------------------        -----------------------
gid        | integer                     | not null default        
nextval('counties_gid_seq'::regclass)
objectid_1 | integer                     | 
objectid   | integer                     | 
state      | character varying(2)        | 
cwa        | character varying(9)        | 
countyname | character varying(24)       | 
fips       | character varying(5)        | 
time_zone  | character varying(2)        | 
fe_area    | character varying(2)        | 
lon        | double precision            | 
lat        | double precision            | 
the_geom   | geometry(MultiPolygon,4269) | 
Indexes:
"counties_pkey" PRIMARY KEY, btree (gid)
"counties_gix" gist (the_geom)
"county_cwa_idx" btree (cwa)
"countyname_cwa_idx" btree (countyname)

У меня есть запрос, который вычисляет общее количество строк в день года (месяц-день), охватывающего30 лет.С помощью Stackoverflow запрос на получение этих показателей работает нормально.Вот запрос и результаты, используя следующую функцию.

Функция:

CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT to_char($1, 'MMDD')::int$$;

Запрос:

SELECT d.mmdd, COALESCE(ct.ct, 0) AS total_count
FROM  (
SELECT f_mmdd(d::date) AS mmdd  -- ignoring the year
FROM   generate_series(timestamp '2018-01-01'  -- any dummy year
                    , timestamp '2018-12-31'
                    , interval '1 day') d
) d
LEFT  JOIN (
SELECT f_mmdd(time::date) AS mmdd, count(*) AS ct
FROM   counties c
JOIN   ltg_data d ON ST_contains(c.the_geom, d.ltg_geom)
WHERE  cwa = 'MFR'
GROUP  BY 1
) ct USING (mmdd)
ORDER  BY 1;

Результаты:

mmdd       total_count
725 |        2126
726 |         558
727 |           2
728 |           2
729 |           2
730 |           0
731 |           0
801 |           0
802 |          10

Желаемые результаты: я пытаюсь найти другую статистическую информацию о количестве дней в году.Например, я знаю 25 июля (725 в таблице ниже), что общее количество за многие годы в таблице - 2126. То, что я ищу, - это максимальное суточное число за 25 июля (725),%лет, когда этот день не равен нулю, мин, процент лет, где count (*) не равен нулю, процентили (10-й процентиль, 25-й процентиль, 50-й процентиль, 75-й процентиль, 90-й процентиль и stdev также будут полезны).Было бы хорошо посмотреть, в каком году произошло max_daily.Я предполагаю, что если бы не было подсчетов за этот день за все годы, год_max_daily был бы пустым или нулевым.

mmdd       total_count  max daily  year_max_daily   percent_years_count_not_zero  10th percentile_daily   90th percentile_daily
725 |        2126         1000          1990                 30                          15                   900
726 |         558          120          1992                 20                          10                   80
727 |           2            1          1991                 2                            0                   1
728 |           2            1          1990                 2                            0                   1
729 |           2            1          1989                 2                            0                   1
730 |           0            0                               0                            0                   0 
731 |           0            0                               0                            0                   0 
801 |           0            0                               0                            0                   0
802 |          10           10          1990                 0                            1                   8

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

Попытка:

SELECT AVG(CAST(total_count as FLOAT)), day
FROM
(
SELECT d.mmdd as day, COALESCE(ct.ct, 0) as total_count
FROM (
SELECT f_mmdd(d::date) AS mmdd
FROM generate_series(timestamp '2018-01-01', timestamp '2018-12-31',     interval '1 day') d
) d
LEFT JOIN (

SELECT mmdd, avg(q.ct) FROM (

SELECT f_mmdd((time at time zone 'utc+12')::date) as mmdd, count(*) as ct
FROM counties c
JOIN ltg_data d on ST_contains(c.the_geom, d.ltg_geom)
WHERE cwa = 'MFR'
GROUP BY 1
) 

) as q

ct USING (mmdd)
ORDER BY 1

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 23 мая 2018

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

Я использую CTE ниже, чтобы сделать запрос читабельным.Если вы хотите, вы можете поместить все это в один огромный запрос.Я бы порекомендовал выполнить запрос шаг за шагом, CTE-by-CTE и изучить промежуточные результаты, чтобы понять, как он работает.

CTE_Dates - это простой список всех возможных дат за 30 лет.

CTE_DailyCounts - это список основных подсчетов за каждый день в течение 30 лет (я взял ваш существующий запрос для этого).

CTE_FullStats снова список всех дат вместе с некоторымиСтатистика рассчитывается для каждого (месяц, день) с использованием оконных функций с разбиением по месяцам, дням.ROW_NUMBER там используется для получения даты, когда число было наибольшим для каждого года.

Окончательный запрос выбирает только одну строку с наибольшим количеством для года вместе с остальной информацией.

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

WITH
CTE_Dates
AS
(
    SELECT
        d::date AS dt
        ,EXTRACT(MONTH FROM d::date) AS dtMonth
        ,EXTRACT(DAY FROM d::date) AS dtDay
        ,EXTRACT(YEAR FROM d::date) AS dtYear
    FROM
        generate_series(timestamp '1988-01-01', timestamp '2018-12-31', interval '1 day') AS d
        -- full range of possible dates
)
,CTE_DailyCounts
AS
(
    SELECT
        time::date AS dt
        ,count(*) AS ct
    FROM
        counties c
        INNER JOIN ltg_data d ON ST_contains(c.the_geom, d.ltg_geom)
    WHERE cwa = 'MFR'
    GROUP BY time::date
)
,CTE_FullStats
AS
(
    SELECT
        CTE_Dates.dt
        ,CTE_Dates.dtMonth
        ,CTE_Dates.dtDay
        ,CTE_Dates.dtYear
        ,CTE_DailyCounts.ct
        ,SUM(CTE_DailyCounts.ct) OVER (PARTITION BY dtMonth, dtDay) AS total_count
        ,MAX(CTE_DailyCounts.ct) OVER (PARTITION BY dtMonth, dtDay) AS max_daily
        ,SUM(CASE WHEN CTE_DailyCounts.ct > 0 THEN 1 ELSE 0 END) OVER (PARTITION BY dtMonth, dtDay) AS nonzero_day_count
        ,COUNT(*) OVER (PARTITION BY dtMonth, dtDay) AS years_count
        ,100.0 * SUM(CASE WHEN CTE_DailyCounts.ct > 0 THEN 1 ELSE 0 END) OVER (PARTITION BY dtMonth, dtDay) 
        / COUNT(*) OVER (PARTITION BY dtMonth, dtDay) AS percent_years_count_not_zero
        ,ROW_NUMBER() OVER (PARTITION BY dtMonth, dtDay ORDER BY CTE_DailyCounts.ct DESC) AS rn
    FROM
        CTE_Dates
        LEFT JOIN CTE_DailyCounts ON CTE_DailyCounts.dt = CTE_Dates.dt
)
SELECT
    dtMonth
    ,dtDay
    ,total_count
    ,max_daily
    ,dtYear AS year_max_daily
    ,percent_years_count_not_zero
FROM
    CTE_FullStats
WHERE
    rn = 1
ORDER BY
    dtMonth
    ,dtDay
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...