PostgreSQL-как использовать первое значение()?
этот ответ показывает, как создавать высокие/низкие/Открытые / Закрытые значения из тикера:
получить агрегаты для произвольных интервалов времени
Я пытаюсь реализовать решение на основе этого (стр. 9.2), но мне трудно получить правильное значение для first_value()
.
до сих пор я пробовал два запроса:
SELECT
cstamp,
price,
date_trunc('hour',cstamp) AS h,
floor(EXTRACT(minute FROM cstamp) / 5) AS m5,
min(price) OVER w,
max(price) OVER w,
first_value(price) OVER w,
last_value(price) OVER w
FROM trades
Where date_trunc('hour',cstamp) = timestamp '2013-03-29 09:00:00'
WINDOW w AS (
PARTITION BY date_trunc('hour',cstamp), floor(extract(minute FROM cstamp) / 5)
ORDER BY date_trunc('hour',cstamp) ASC, floor(extract(minute FROM cstamp) / 5) ASC
)
ORDER BY cstamp;
вот часть результата:
cstamp price h m5 min max first last
"2013-03-29 09:19:14";77.00000;"2013-03-29 09:00:00";3;77.00000;77.00000;77.00000;77.00000
"2013-03-29 09:26:18";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000
"2013-03-29 09:29:41";77.80000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000
"2013-03-29 09:29:51";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.80000;77.00000
"2013-03-29 09:30:04";77.00000;"2013-03-29 09:00:00";6;73.99004;77.80000;73.99004;73.99004
как вы можете видеть, 77.8 это не то, что я считаю правильным значением для first_value()
, который должен быть 77.0.
Я думал, что это может быть связано с неоднозначным ORDER BY
на WINDOW
, поэтому я изменил это на
ORDER BY cstamp ASC
но это, кажется, расстроило PARTITION
а также:
cstamp price h m5 min max first last
"2013-03-29 09:19:14";77.00000;"2013-03-29 09:00:00";3;77.00000;77.00000;77.00000;77.00000
"2013-03-29 09:26:18";77.00000;"2013-03-29 09:00:00";5;77.00000;77.00000;77.00000;77.00000
"2013-03-29 09:29:41";77.80000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.00000;77.80000
"2013-03-29 09:29:51";77.00000;"2013-03-29 09:00:00";5;77.00000;77.80000;77.00000;77.00000
"2013-03-29 09:30:04";77.00000;"2013-03-29 09:00:00";6;77.00000;77.00000;77.00000;77.00000
так как значения для max и last now в раздел.
что я делаю не так? Может кто-нибудь помочь мне лучше понять отношения между PARTITION
и ORDER
внутри WINDOW
?
хотя у меня есть ответ, вот обрезанный pg_dump, который позволит любому воссоздать таблицу. Единственное, что отличается, - это имя таблицы.
CREATE TABLE wtest (
cstamp timestamp without time zone,
price numeric(10,5)
);
COPY wtest (cstamp, price) FROM stdin;
2013-03-29 09:04:54 77.80000
2013-03-29 09:04:50 76.98000
2013-03-29 09:29:51 77.00000
2013-03-29 09:29:41 77.80000
2013-03-29 09:26:18 77.00000
2013-03-29 09:19:14 77.00000
2013-03-29 09:19:10 77.00000
2013-03-29 09:33:50 76.00000
2013-03-29 09:33:46 76.10000
2013-03-29 09:33:15 77.79000
2013-03-29 09:30:08 77.80000
2013-03-29 09:30:04 77.00000
.
3 ответов
все функции, которые вы использовали, действуют на оконную раму, а не на раздел. Если опущено, конец кадра-это текущая строка. Чтобы сделать рамку окна всей секцией, объявите ее в предложении frame (range...
):
SELECT
cstamp,
price,
date_trunc('hour',cstamp) AS h,
floor(EXTRACT(minute FROM cstamp) / 5) AS m5,
min(price) OVER w,
max(price) OVER w,
first_value(price) OVER w,
last_value(price) OVER w
FROM trades
Where date_trunc('hour',cstamp) = timestamp '2013-03-29 09:00:00'
WINDOW w AS (
PARTITION BY date_trunc('hour',cstamp) , floor(extract(minute FROM cstamp) / 5)
ORDER BY cstamp
range between unbounded preceding and unbounded following
)
ORDER BY cstamp;
вот быстрый запрос, чтобы проиллюстрировать поведение:
select
v,
first_value(v) over w1 f1,
first_value(v) over w2 f2,
first_value(v) over w3 f3,
last_value (v) over w1 l1,
last_value (v) over w2 l2,
last_value (v) over w3 l3,
max (v) over w1 m1,
max (v) over w2 m2,
max (v) over w3 m3,
max (v) over () m4
from (values(1),(2),(3),(4)) t(v)
window
w1 as (order by v),
w2 as (order by v rows between unbounded preceding and current row),
w3 as (order by v rows between unbounded preceding and unbounded following)
вывод вышеуказанного запроса можно увидеть здесь (SQLFiddle здесь):
| V | F1 | F2 | F3 | L1 | L2 | L3 | M1 | M2 | M3 | M4 |
|---|----|----|----|----|----|----|----|----|----|----|
| 1 | 1 | 1 | 1 | 1 | 1 | 4 | 1 | 1 | 4 | 4 |
| 2 | 1 | 1 | 1 | 2 | 2 | 4 | 2 | 2 | 4 | 4 |
| 3 | 1 | 1 | 1 | 3 | 3 | 4 | 3 | 3 | 4 | 4 |
| 4 | 1 | 1 | 1 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
мало кто думает о неявных кадрах, которые применяются к оконным функциям, которые принимают ORDER BY
предложения. В этом случае windows по умолчанию для frame ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. Подумайте об этом так:
- в строке
v = 1
пролеты рамки заказанного окнаv IN (1)
- в строке
v = 2
рамка заказанного окна охватываетv IN (1, 2)
- в строке
v = 3
рамка заказанного окна охватываетv IN (1, 2, 3)
- в строке
v = 4
рамка заказанного окна охватываетv IN (1, 2, 3, 4)
если вы хотите предотвратить это поведение, у вас есть два варианта:
- использовать явное
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
статьи приказал окне функции - использовать нет
ORDER BY
предложение в тех оконных функциях, которые позволяют опустить их (какMAX(v) OVER()
)
более подробная информация объясняется в этой статье LEAD()
, LAG()
, FIRST_VALUE()
и LAST_VALUE()
результат max()
поскольку функция окна основана на определение фрейма.
определение фрейма по умолчанию (с ORDER BY
) от начала кадра до последний узел текущей строки (включая текущую строку и, возможно, больше строк рейтинга одинаково по данным ORDER BY
). В отсутствие ORDER BY
(как в моем ответе, на который вы ссылаетесь), или если ORDER BY
рассматривает каждую строку в разделе как равную (например в первом примере) все строки в разделе являются одноранговыми и max()
дает тот же результат для каждой строки в разделе, эффективно учитывая все строк раздела.
вариант кадрирования по умолчанию:
RANGE UNBOUNDED PRECEDING
, который является то же самое, чтоRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. СORDER BY
, это устанавливает фрейм как все строки от начала раздела вверх по текущей строке последний Пэр. БезORDER BY
, все строки разделы включены в оконную рамку, так как все строки становятся одноранговые узлы текущей строки.
жирным выделено мной.
простым решением было бы пропустить ORDER BY
в определении окна-так же, как я продемонстрировал в Примере, на который вы ссылаетесь.
все кровавые подробности о спецификациях кадров в главе Функция Окна Звонки в руководстве.