SQL - Vertica: как создавать ежедневные строки с большинством данных предыдущей даты
У меня есть базовая таблица, как показано ниже:
score_upd (Upd_dt,Url,Score) AS (
SELECT DATE '2019-07-26','A','x'
UNION ALL SELECT DATE '2019-07-26','B','alpha'
UNION ALL SELECT DATE '2019-08-01','A','y'
UNION ALL SELECT DATE '2019-08-01','B','beta'
UNION ALL SELECT DATE '2019-08-03','A','z'
UNION ALL SELECT DATE '2019-08-03','B','gamma'
)
Upd_dt URL Score
2019-07-26 A x
2019-07-26 B alpha
2019-08-01 A y
2019-08-01 B beta
2019-08-03 A z
2019-08-03 B gamma
И я хочу создать таблицу на уровне ежедневного URL, используя значение самой предыдущей даты для новых строк, результат должен выглядеть следующим образом:
score_upd (Upd_dt,Url,Score) AS (
SELECT DATE '2019-07-26','A','x'
UNION ALL SELECT DATE '2019-07-26','B','alpha'
UNION ALL SELECT DATE '2019-07-27','A','x'
UNION ALL SELECT DATE '2019-07-27','B','alpha'
UNION ALL SELECT DATE '2019-07-28','A','x'
UNION ALL SELECT DATE '2019-07-28','B','alpha'
UNION ALL SELECT DATE '2019-07-29','A','x'
UNION ALL SELECT DATE '2019-07-29','B','alpha'
UNION ALL SELECT DATE '2019-07-30','A','x'
UNION ALL SELECT DATE '2019-07-30','B','alpha'
UNION ALL SELECT DATE '2019-07-31','A','x'
UNION ALL SELECT DATE '2019-07-31','B','alpha'
UNION ALL SELECT DATE '2019-08-01','A','y'
UNION ALL SELECT DATE '2019-08-01','B','beta'
UNION ALL SELECT DATE '2019-08-02','A','y'
UNION ALL SELECT DATE '2019-08-02','B','beta'
UNION ALL SELECT DATE '2019-08-03','A','z'
UNION ALL SELECT DATE '2019-08-03','B','gamma'
UNION ALL SELECT DATE '2019-08-04','A','z'
UNION ALL SELECT DATE '2019-08-04','B','gamma'
UNION ALL SELECT DATE '2019-08-05','A','z'
UNION ALL SELECT DATE '2019-08-05','B','gamma'
)
Что выглядит так:
Upd_dt URL Score
2019-07-26 A x
2019-07-26 B alpha
2019-07-27 A x
2019-07-27 B alpha
2019-07-28 A x
2019-07-28 B alpha
2019-07-29 A x
2019-07-29 B alpha
2019-07-30 A x
2019-07-30 B alpha
2019-07-31 A x
2019-07-31 B alpha
2019-08-01 A y
2019-08-01 B beta
2019-08-02 A y
2019-08-02 B beta
2019-08-03 A z
2019-08-03 B gamma
2019-08-04 A z
2019-08-04 B gamma
2019-08-05 A z
2019-08-05 B gamma
.
.
.
Текущий процесс: я построил таблицу ежедневных измерений с 26.07.2019 по сегодняшний день:
/* ВЫБРАТЬ ДАТЫ CAST(slice_time КАК ДАТА) ИЗ testcalendar mtc TIMESERIES slice_time как '1 день' ВЫШЕ (ORDER BY CAST(mtc.dates as TIMESTAMP)); */
так я получаю:
Даты
2019-07-26
2019-07-27
2019-07-28
2019-07-29
.
.
.
2019-10-12 (сегодня)
Я думаю, могу ли я использовать такую функцию, как "интерполировать предыдущее значение", чтобы присоединиться к моей первой таблице по датам, чтобы сгенерировать недостающие дни, используя значения из большинства данных предыдущей даты, пока это не удалось.
В результате не было создано строк за пропущенные дни.
Пожалуйста, дайте мне знать, есть ли у кого-нибудь лучшее представление об этом.
Спасибо!
1 ответ
В качестве первого предупреждения: храните "ежедневные фотографии" только тогда, когда они действительно необходимы. В моем прошлом у меня однажды получалось слишком много 364 строки в год, так как значения менялись только один раз в год. В Vertica это требует лицензии, а также процессора и времени для объединения и группировки...
Но в остальном - хорошее начало.
Но вы можете применять TIMESERIES, не создавая календаря.
Хитрость заключается в том, чтобы вручную "экстраполировать" то, что вы можете INTERPOLATE
автоматически.
Добавьте встроенную таблицу заполнения, которая содержит новейшее значение для каждого URL-адреса, но укажите его CURRENT_DATE
вместо самой новой фактической даты - с использованием специфической аналитической предельной оговорки Vertica LIMIT 1 OVER(PARTITION BY url ORDER BY upd_dt DESC)
.
UNION SELECT эту таблицу заполнения вашим вводом и примените предложение TIMESERIES к этому UNION SELECT.
Вот так:
WITH
-- your input ...
score_upd (Upd_dt,Url,Score) AS (
SELECT DATE '2019-07-26','A','x'
UNION ALL SELECT DATE '2019-07-26','B','alpha'
UNION ALL SELECT DATE '2019-08-01','A','y'
UNION ALL SELECT DATE '2019-08-01','B','beta'
UNION ALL SELECT DATE '2019-08-03','A','z'
UNION ALL SELECT DATE '2019-08-03','B','gamma'
)
-- real WITH clause would start here ...
,
-- newest row per Url, just with current date
pad_newest AS (
SELECT
CURRENT_DATE
, url
, score
FROM score_upd
LIMIT 1 OVER(PARTITION BY url ORDER BY upd_dt DESC)
)
,
with_newest AS (
SELECT
*
FROM score_upd
UNION ALL
SELECT *
FROM pad_newest
)
SELECT
ts_dt::DATE AS upd_dt
, url AS url
, TS_FIRST_VALUE(score) AS score
FROM with_newest
TIMESERIES ts_dt AS '1 day' OVER (
PARTITION BY url ORDER BY upd_dt::TIMESTAMP
)
ORDER BY 1,2
;