2016-11-16 1 views
2

에 의해 영감을 받았습니다. 지난 해 5 분 간격으로 계산 된 AVG를 반환하는 다음 쿼리를 작성했습니다. 행이 특정 시간 범위에 맞지 않는 경우 내가하고 싶은 무엇그룹화되지 않은 데이터를 삽입하는 방법

모든 5 분 null로 설정된 경우 간격하고있다.

with intervals as (select 
        (select min("timestamp") from public.hst_energy_d) + n AS start_timestamp, 
        (select min("timestamp") from public.hst_energy_d) + n + 299 AS end_timestamp 
        from generate_series(extract(epoch from now())::BIGINT - 10596096000, extract(epoch from now())::BIGINT, 300) n) 
(SELECT AVG(meas."Al1") as "avg", islots.start_timestamp AS "timestamp" 
FROM public.hst_energy_d meas 
    RIGHT OUTER JOIN intervals islots 
    on meas.timestamp >= islots.start_timestamp and meas.timestamp <= islots.end_timestamp 
WHERE 
    meas.idinstrum = 4 
    AND 
    meas.id_device = 122 
    AND 
    meas.timestamp > extract(epoch from now()) - 10596096000 
GROUP BY islots.start_timestamp, islots.end_timestamp 
ORDER BY timestamp); 

답변

1

나는 당신이 뭘 하려는지 볼 생각과 접근 방식에 따라하기 더 쉬울 would't 자유롭게 interval '5 minutes'를 사용하는 경우 궁금 : 분별의 눈은 수도 그런데

with times as ( -- find the first date in the dataset, up to today 
    select 
    date_trunc ('minutes', min("timestamp")) - 
    mod (extract ('minutes' from min("timestamp"))::int, 5) * interval '1 minute' as bt, 
    date_trunc ('minutes', current_timestamp) - 
    mod (extract ('minutes' from current_timestamp)::int, 5) * interval '1 minute' as et 
    from hst_energy_d 
    where 
    idinstrum = 4 and 
    id_device = 122 
), -- generate every possible range between these dates 
ranges as (
    select 
    generate_series(bt, et, interval '5 minutes') as range_start 
    from times 
), -- normalize your data to which 5-minut interval it belongs to 
rounded_hst as (
    select 
    date_trunc ('minutes', "timestamp") - 
    mod (extract ('minutes' from "timestamp")::int, 5) * interval '1 minute' as round_time, 
    * 
    from hst_energy_d 
    where 
    idinstrum = 4 and 
    id_device = 122 
) 
select 
    r.range_start, r.range_start + interval '5 minutes' as range_end, 
    avg (hd."Al1") 
from 
    ranges r 
    left join rounded_hst hd on 
    r.range_start = hd.round_time 
group by 
    r.range_start 
order by 
    r.range_start 

을 CTE rounded_hst을 왜 귀찮게 사용하는지 궁금하고 조인에 "사이"를 사용하지 않는 것이 좋습니다. 테스트하고 관찰 한 모든 것에서 데이터베이스는 모든 가능성을 폭발시킨 다음 where 절에 해당하는 조건 (즉, 필터링 된 데카르트 식)을 테스트합니다. 이 많은 간격 동안, 그것은 살인자가 될 것입니다.

각 데이터를 가장 가까운 5 분으로 잘라내어 표준 SQL 조인을 허용합니다. 나는 둘 다 테스트 해보길 바란다. 나는 당신이 내가 의미하는 것을 보게 될 것이라고 생각한다.

- 편집 2016년 11월 17일 - 고려 OP에서

해결 시간은 숫자가 아닌 날짜입니다

with times as ( -- find the first date in the dataset, up to today 
    select 
     date_trunc('minutes', to_timestamp(min("timestamp"))::timestamp) - 
     mod(extract ('minutes' from to_timestamp(min("timestamp"))::timestamp)::int, 5) * interval '1 minute' as bt, 
     date_trunc('minutes', current_timestamp::timestamp) - 
     mod(extract ('minutes' from (current_timestamp)::timestamp)::int, 5) * interval '1 minute' as et 
    from hst_energy_d 
    where 
     idinstrum = 4 and 
     id_device = 122 
), -- generate every possible range between these dates 
    ranges as (
     select 
     generate_series(bt, et, interval '5 minutes') as range_start 
     from times 
), -- normalize your data to which 5-minute interval it belongs to 
    rounded_hst as (
     select 
     date_trunc ('minutes', to_timestamp("timestamp")::timestamp)::timestamp - 
     mod (extract ('minutes' from (to_timestamp("timestamp")::timestamp))::int, 5) * interval '1 minute' as round_time, 
     * 
     from hst_energy_d 
     where 
     idinstrum = 4 and 
     id_device = 122 
) 
select 
    extract('epoch' from r.range_start)::bigint, extract('epoch' from r.range_start + interval '5 minutes')::bigint as range_end, 
    avg (hd."Al1") 
from 
    ranges r 
    left join rounded_hst hd on 
          r.range_start = hd.round_time 
group by 
    r.range_start 
order by 
    r.range_start; 
+0

무엇 깔끔한 쿼리! 불행히도'timestamp'는 진짜'timestamp' 대신에'BIGINT'입니다. 그러므로 타임 스탬프 대신 숫자를 사용한 수학 – Bertuz

+0

bigint를 사용하기 위해 제안 된 코드를 수정했습니다. 그러나 이것이 여전히 가능할 지 확신하지 못합니다 더 가벼운 SQL을 활용하십시오. [새로운 SQL 개요] (https://gist.github.com/bertuz/5544663474b8a0850dcede03d1903a02) 한 번 둘러 보시고 피드백을 주시겠습니까? Plus : 솔루션으로 Postgres 성능을 향상시키는 방법에 대해 이야기했습니다. 어떻게 분석 했습니까? 'EXPLAIN'을 사용하여? 여기 내 쿼리가 수행하는 [쿼리 계획] (https://gist.github.com/bertuz/5f06ab81cde3e78231c94c3a76ad20f8)입니다. 실제로 hst_energy_d에서 두 번의 스캔을 수행합니까? 그게 * 많은 *! 감사합니다 – Bertuz

+0

좋아요,'EXPLAIN'은 자체적으로 말합니다 : 귀하의 솔루션 비용은'48.47'이고, 내 비용은'247.17'입니다. – Bertuz

관련 문제