Как обеспечить, чтобы каждая дата и развертывание присутствовали, а оконная функция не пропускала дни, потому что данные отсутствуют? - PullRequest
0 голосов
/ 16 апреля 2020

Работая в Афине, у меня есть запрос, который генерирует таблицу с несколькими показателями для каждой итерации даты и развертывания.

WITH
  core AS (
   SELECT /* create dataset for window functions to work on */
     "deployment"
   , "macaddress"
   , "date"
   FROM 
     (
      SELECT /* de-dupe the base dataset based on a macaddress being valid once per day per deployment */
        "_deployment" "deployment"
      , "macaddress"
      , "date"("timestamp") "date"
      , "row_number"() OVER (PARTITION BY "_deployment", "macaddress" ORDER BY "date"("timestamp") ASC) "rn"
      FROM
        registration
   ) 
   WHERE (CAST("rn" AS varchar(2)) = '1')
) 
SELECT /* window functions to aggregate */
  "count"("macaddress") "registrations"
, "deployment"
, "date"
, "lag"("count"("macaddress"), 1) OVER (PARTITION BY "deployment" ORDER BY "date" ASC) "yesterdayCount"
, "sum"("count"("macaddress")) OVER (PARTITION BY "deployment" ORDER BY "date" ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) "Past7Days"
, "sum"("count"("macaddress")) OVER (PARTITION BY "deployment" ORDER BY "date" ASC ROWS BETWEEN 13 PRECEDING AND 7 PRECEDING) "7daysTarget"
, "sum"("count"("macaddress")) OVER (PARTITION BY "deployment" ORDER BY "date" ASC ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) "Past30Days"
, "sum"("count"("macaddress")) OVER (PARTITION BY "deployment" ORDER BY "date" ASC ROWS BETWEEN 59 PRECEDING AND 30 PRECEDING) "30daysTarget"
, "avg"("count"("macaddress")) OVER (PARTITION BY "deployment" ORDER BY "date" ASC ROWS BETWEEN 9 PRECEDING AND CURRENT ROW) "10DayTrend"
FROM
  core
GROUP BY "deployment", "date"

Проблема, с которой я сталкиваюсь, связана с тем, что не каждое развертывание имеет данные для каждой даты, таким образом, оконные функции не работают должным образом, они суммируют предыдущие 7 rows, а не предыдущие 7 days.

Вывод, который я получаю, представляет собой таблицу со строкой для каждого date между самым ранним и самым последним в наборе данных (последний date будет продолжать двигаться, таблица обновляется каждую ночь) и каждый deployment присутствует в наборе данных, есть ли данные в наборе данных или нет.

Итак, если в развертывании 1 есть данные за следующие дни:

2020-04-1
2020-04-2
2020-04-3
2020-04-5
2020-04-6
2020-04-7
2020-04-8

Я бы хотел, чтобы поле Past7Days для 2020-04-8 было бы суммой 2020-04-2 до 2020-04-08. На данный момент результат представляет собой сумму от 2020-04-01 до 2020-04-08, поскольку он просматривает строки, а не даты, а 2020-04-4 отсутствует.

Окончательная таблица должна иметь формат:

registrations | deployment | date | yesterdayCount | Past7Days | 7daysTarget | Past30Days | 30daysTarget | 10DayTrend

и не имеют пробелов для даты или развертывания.

Моя рабочая теория заключается в том, что мне нужно установить sh это в самом внутреннем внутреннем операторе SELECT (дедуплицирующем). У меня есть таблица календаря, и я присоединяюсь к ней, но меня пугает тот факт, что в календаре нет поля deployment, и поэтому соединение является неполным и состоит только из date. Если это вообще возможно, я хочу избежать таблицы календаря для каждого развертывания.

Заранее благодарю за любую помощь.

1 Ответ

0 голосов
/ 16 апреля 2020

просто создайте свой календарь развертывания путем перекрестного объединения развертываний с календарным столом. Что-то вроде

WITH
  core AS (
   SELECT /* create dataset for window functions to work on */
     "deployment"
   , "macaddress"
   , "date"
   FROM 
     (
      SELECT /* de-dupe the base dataset based on a macaddress being valid once per day per deployment */
        "_deployment" "deployment"
      , "macaddress"
      , "date"("timestamp") "date"
      , "row_number"() OVER (PARTITION BY "_deployment", "macaddress" ORDER BY "date"("timestamp") ASC) "rn"
      FROM
        registration
   ) 
   WHERE (CAST("rn" AS varchar(2)) = '1')
) ,
deploymentcalendar as (
select t.deployment,ct.date 
from (select distinct deploymet from core) t
cross join calendar_table ct
)
SELECT /* window functions to aggregate */
  "count"("macaddress") "registrations"
, "deployment"
, "date"
, "lag"("count"("macaddress"), 1) OVER (PARTITION BY dc."deployment" ORDER BY "date" ASC) "yesterdayCount"
, "sum"("count"("macaddress")) OVER (PARTITION BY dc."deployment" ORDER BY dc."date" ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) "Past7Days"
, "sum"("count"("macaddress")) OVER (PARTITION BY dc."deployment" ORDER BY dc."date" ASC ROWS BETWEEN 13 PRECEDING AND 7 PRECEDING) "7daysTarget"
, "sum"("count"("macaddress")) OVER (PARTITION BY dc."deployment" ORDER BY dc."date" ASC ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) "Past30Days"
, "sum"("count"("macaddress")) OVER (PARTITION BY dc."deployment" ORDER BY dc."date" ASC ROWS BETWEEN 59 PRECEDING AND 30 PRECEDING) "30daysTarget"
, "avg"("count"("macaddress")) OVER (PARTITION BY dc."deployment" ORDER BY dc."date" ASC ROWS BETWEEN 9 PRECEDING AND CURRENT ROW) "10DayTrend"
FROM
  core
RIGHT JOIN deploymentcalendar dc on dc.deployment=core.deployment and dc.date=core.date
GROUP BY core."deployment", core."date"
...