PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да получите средни стойности за времеви интервали в Postgres

Дизайн на DB

Докато можете работа с отделна дата и време колони, наистина няма предимство пред единичен timestamp колона. Бих се адаптирал:

ALTER TABLE tbl ADD column ts timestamp;
UPDATE tbl SET ts = date + time;  -- assuming actual date and time types
ALTER TABLE tbl DROP column date, DROP column time;

Ако датата и часът не са действителната дата и време типове данни, използвайте to_timestamp() . Свързани:

Заявка

Тогава заявката е малко по-проста:

SELECT *
FROM  (
   SELECT sn, generate_series(min(ts), max(ts), interval '5 min') AS ts
   FROM   tbl
   WHERE  sn = '4as11111111'
   AND    ts >= '2018-01-01'
   AND    ts <  '2018-01-02'
   GROUP  BY 1
   ) grid
CROSS  JOIN LATERAL (
   SELECT round(avg(vin1), 2) AS vin1_av
        , round(avg(vin2), 2) AS vin2_av
        , round(avg(vin3), 2) AS vin3_av
   FROM   tbl
   WHERE  sn =  grid.sn
   AND    ts >= grid.ts
   AND    ts <  grid.ts + interval '5 min'
   ) avg;

db<>fiddle тук

Генерирайте мрежа от начални времена в първата подзаявка grid , протичащ от първата до последната квалификация ред в дадения период от време.

Присъединете се към редове, които попадат във всеки дял с LATERAL присъединете и незабавно обобщете средните стойности в подзаявката ср. . Благодарение на агрегатите, това винаги връща ред, дори ако не са намерени записи. Средните стойности по подразбиране са NULL в този случай.

Резултатът включва всички времеви интервали между първия и последния квалифициращ ред в дадената времева рамка. Различни други резултатни композиции също биха имали смисъл. Като включване на всички времеви интервали в дадената времева рамка или само времеви интервали с действителни стойности. Всички възможни, трябваше да избера една интерпретация.

Индекс

Имайте поне този многоколонен индекс:

CRATE INDEX foo_idx ON tbl (sn, ts);

Или на (sn, ts, vin1, vin2, vin3) за да позволи сканиране само на индекс - ако са изпълнени някои предварителни условия и особено ако редовете на таблицата са много по-широки, отколкото в демонстрацията.

Тясно свързано:

Въз основа на вашата оригинална таблица

Както е поискано и изяснено в коментара и по-късно актуализиран отново във въпроса, за да включи колоните mac и loc . Предполагам, че искате отделни средни стойности за (mac, loc) .

дата и време все още са отделни колони, vin* колоните са от тип float и изключете времеви интервали без редове:

Актуализираната заявка също премества функцията за връщане на набор generate_series() към ОТ списък, който е по-чист преди Postgres 10:

SELECT t.mac, sn.sn, t.loc, ts.ts::time AS time, ts.ts::date AS date
     , t.vin1_av, t.vin2_av, t.vin3_av
FROM  (SELECT text '4as11111111') sn(sn)  -- provide sn here once
CROSS  JOIN LATERAL (
   SELECT min(date+time) AS min_ts, max(date+time) AS max_ts
   FROM   tbl
   WHERE  sn = sn.sn
   AND    date+time >= '2018-01-01 0:0'   -- provide time frame here
   AND    date+time <  '2018-01-02 0:0'
   ) grid
CROSS  JOIN LATERAL generate_series(min_ts, max_ts, interval '5 min') ts(ts)
CROSS  JOIN LATERAL (
   SELECT mac, loc
        , round(avg(vin1)::numeric, 2) AS vin1_av  -- cast to numeric for round()
        , round(avg(vin2)::numeric, 2) AS vin2_av  -- but rounding is optional
        , round(avg(vin3)::numeric, 2) AS vin3_av
   FROM   tbl
   WHERE  sn = sn.sn
   AND    date+time >= ts.ts
   AND    date+time <  ts.ts + interval '5 min'
   GROUP  BY mac, loc
   HAVING count(*) > 0  -- exclude empty slots
   ) t;

Създайте индекс на израз с няколко колони, който да поддържа това:

CRATE INDEX bar_idx ON tbl (sn, (date+time));

db<>fiddle тук

Но бих предпочел да използвам timestamp през цялото време.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Има ли някакъв начин за прехвърляне на тип данни postgresql 9.3, така че да може да засегне само едната страна

  2. Първата и последната стойност агрегатни функции в postgresql, които работят правилно с NULL стойности

  3. Дублираната стойност на ключ нарушава уникалното ограничение, CakePHP

  4. Основна/кръстосана таблица с повече от една колона със стойности

  5. Как да изчистите коментари от необработен sql файл