Как вы получаете MAX () и SUM () значений между значениями STRING? - PullRequest
1 голос
/ 28 февраля 2020

У меня есть данные, которые выглядят так:

metric_date      location  id    value
20/02/07 13:00   ATL       A      34
20/02/07 13:05   ATL       B      12
20/02/07 13:10   ATL       B      02
20/02/07 13:15   ATL       A      15
20/02/07 13:20   ATL       A      00         
20/02/07 13:25   ATL       A      00
20/02/07 13:30   ATL       A      12
20/02/07 13:35   ATL       B      12
20/02/07 13:40   ATL       A      23
20/02/07 13:45   ATL       B      03
20/02/07 13:50   ATL       A      00
20/02/07 13:55   ATL       A      00

Мне нужно найти max (значение) и -SUM (значение), где «id» - это «B» - каждого раздела между нулями - столбцы значений, чтобы получить SUM () / MAX () = success_rate

Я пытался:

SELECT 
      CASE
       WHEN DATE(metric_date) = lag(DATE(metric_date), 1) OVER (ORDER BY DATE(metric_date)) 
            AND building = lag(building, 1) OVER (ORDER BY date)
       THEN 1
      END AS work_period
    , CASE
        WHEN LAG(value, 1) OVER (ORDER BY date) = 0
             AND LEAD(value, 1) OVER (ORDER BY date) > 0
        THEN LAG(work_period, 1) + 1
        WHEN LAG(SUM(metric_value), 1) OVER (ORDER BY metric_date) > 0
        THEN LAG(work_period, 1)
       END section

Мне нужно, чтобы результаты выглядели так:

location  section   max   sum   success_rate
ATL         1       34    14    0.4118
ATL         2       23    15    0.6522

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

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

SELECT min(location) AS location
     , row_number() OVER (ORDER BY grp) AS section
     , max(value) AS max
     , sum(value) FILTER (WHERE id = 'B') AS sum
     , round(sum(value) FILTER (WHERE id = 'B')
           / max(value)::numeric, 4) AS success_rate
FROM (
   SELECT *, count(*) FILTER (WHERE value = 0) OVER (ORDER BY metric_date) AS grp
   FROM   tbl
   ) sub
WHERE  value <> 0
GROUP  BY grp;

db <> fiddle здесь

В частности, не группировка по location - что может иметь смысл ...

Подробное объяснение во многих связанных ответах:

Для максимальной производительности рассмотрим процедурное решение в данном конкретном случае (как правило, решения на основе множеств быстрее), поскольку это можно сделать с помощью одного последовательного сканирования таблицы. Например:

0 голосов
/ 28 февраля 2020

Это проблема с пробелами и островами (статья предназначена для SQL сервера, но в равной степени относится к postgresql).

Следующее должно решить вашу проблему

SELECT  Location,
        MAX(Value) AS Max,
        SUM(CASE WHEN id = 'B' THEN Value END) AS Sum,
        1.0 * SUM(CASE WHEN id = 'B' THEN Value END) / MAX(Value) AS SuccesRate
FROM    (   SELECT  *,
                    ROW_NUMBER() OVER(PARTITION BY Location, CASE WHEN Value = 0 THEN 1 ELSE 0 END ORDER BY metric_date) - 
                        ROW_NUMBER() OVER(PARTITION BY Location ORDER BY metric_date) AS GroupingSet
            FROM    T
        ) AS t
WHERE   Value <> 0
GROUP BY Location, GroupingSet;

Ключ генерирует поле для группировки, чтобы идентифицировать острова, что можно сделать, выделив два номера строки для каждой строки:

SELECT  *,
        ROW_NUMBER() OVER(PARTITION BY Location, CASE WHEN Value = 0 THEN 1 ELSE 0 END ORDER BY metric_date) AS RowNumInSubset,
        ROW_NUMBER() OVER(PARTITION BY Location ORDER BY metric_date) AS RowNumInSet
FROM    #T
ORDER BY metric_date

Это приводит к следующему:

metric_date         location    id      value   RowNumInSubset  RowNumInSet 
----------------------------------------------------------------------------
2020-02-07 13:00    ATL         A       34          1               1       
2020-02-07 13:05    ATL         B       12          2               2       
2020-02-07 13:10    ATL         B       2           3               3       
2020-02-07 13:15    ATL         A       15          4               4       
2020-02-07 13:20    ATL         A       0           1               5       
2020-02-07 13:25    ATL         A       0           2               6       
2020-02-07 13:30    ATL         A       12          5               7       
2020-02-07 13:35    ATL         B       12          6               8       
2020-02-07 13:40    ATL         A       23          7               9       
2020-02-07 13:45    ATL         B       3           8               10      
2020-02-07 13:50    ATL         A       0           3               11      
2020-02-07 13:55    ATL         A       0           4               12      

Затем, вычитая RowNumInSet из RowNumInSubset, вы получите константу для вашего islands:

metric_date         location    id      value   RowNumInSubset  RowNumInSet GroupingSet
------------------------------------------------------------------------------------
2020-02-07 13:00    ATL         A       34          1               1           0
2020-02-07 13:05    ATL         B       12          2               2           0
2020-02-07 13:10    ATL         B       2           3               3           0
2020-02-07 13:15    ATL         A       15          4               4           0
------------------------------------------------------------------------------------
2020-02-07 13:20    ATL         A       0           1               5           -4
2020-02-07 13:25    ATL         A       0           2               6           -4
------------------------------------------------------------------------------------
2020-02-07 13:30    ATL         A       12          5               7           -2
2020-02-07 13:35    ATL         B       12          6               8           -2
2020-02-07 13:40    ATL         A       23          7               9           -2
2020-02-07 13:45    ATL         B       3           8               10          -2
------------------------------------------------------------------------------------
2020-02-07 13:50    ATL         A       0           3               11          -8
2020-02-07 13:55    ATL         A       0           4               12          -8

Затем, наконец, вы можете удалить строки, где value = 0, так как это просто точки останова:

metric_date         location    id      value   RowNumInSubset  RowNumInSet GroupingSet
------------------------------------------------------------------------------------
2020-02-07 13:00    ATL         A       34          1               1           0
2020-02-07 13:05    ATL         B       12          2               2           0
2020-02-07 13:10    ATL         B       2           3               3           0
2020-02-07 13:15    ATL         A       15          4               4           0
------------------------------------------------------------------------------------
2020-02-07 13:30    ATL         A       12          5               7           -2
2020-02-07 13:35    ATL         B       12          6               8           -2
2020-02-07 13:40    ATL         A       23          7               9           -2
2020-02-07 13:45    ATL         B       3           8               10          -2

Затем вы можете выполнить агрегирование для каждой группы.

Пример для DB <> Fiddle

...