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

Подреден брой последователни повторения / дубликати

Тестов случай

Първо, по-полезен начин за представяне на вашите данни - или дори по-добре, в sqlfiddle , готов за игра с:

CREATE TEMP TABLE data(
   system_measured int
 , time_of_measurement int
 , measurement int
);

INSERT INTO data VALUES
 (1, 1, 5)
,(1, 2, 150)
,(1, 3, 5)
,(1, 4, 5)
,(2, 1, 5)
,(2, 2, 5)
,(2, 3, 5)
,(2, 4, 5)
,(2, 5, 150)
,(2, 6, 5)
,(2, 7, 5)
,(2, 8, 5);

Опростена заявка

Тъй като остава неясно, приемам само горното като дадено.
След това опростих заявката ви, за да стигнем до:

WITH x AS (
   SELECT *, CASE WHEN lag(measurement) OVER (PARTITION BY system_measured
                               ORDER BY time_of_measurement) = measurement
                  THEN 0 ELSE 1 END AS step
   FROM   data
   )
   , y AS (
   SELECT *, sum(step) OVER(PARTITION BY system_measured
                            ORDER BY time_of_measurement) AS grp
   FROM   x
   )
SELECT * ,row_number() OVER (PARTITION BY system_measured, grp
                             ORDER BY time_of_measurement) - 1 AS repeat_ct
FROM   y
ORDER  BY system_measured, time_of_measurement;

Сега, въпреки че е хубаво и лъскаво да се използва чист SQL, това ще е много по-бързо с функция plpgsql, защото може да го направи с едно сканиране на таблица, където тази заявка се нуждае от поне три сканирания.

По-бързо с функция plpgsql:

CREATE OR REPLACE FUNCTION x.f_repeat_ct()
  RETURNS TABLE (
    system_measured int
  , time_of_measurement int
  , measurement int, repeat_ct int
  )  LANGUAGE plpgsql AS
$func$
DECLARE
   r    data;     -- table name serves as record type
   r0   data;
BEGIN

-- SET LOCAL work_mem = '1000 MB';  -- uncomment an adapt if needed, see below!

repeat_ct := 0;   -- init

FOR r IN
   SELECT * FROM data d ORDER BY d.system_measured, d.time_of_measurement
LOOP
   IF  r.system_measured = r0.system_measured
       AND r.measurement = r0.measurement THEN
      repeat_ct := repeat_ct + 1;   -- start new array
   ELSE
      repeat_ct := 0;               -- start new count
   END IF;

   RETURN QUERY SELECT r.*, repeat_ct;

   r0 := r;                         -- remember last row
END LOOP;

END
$func$;

Обадете се:

SELECT * FROM x.f_repeat_ct();

Не забравяйте да квалифицирате имената на колоните си по всяко време в този вид plpgsql функция, защото използваме същите имена като изходни параметри, които биха имали предимство, ако не са квалифицирани.

Милиарди редове

Ако иматемилиарди на реди , може да искате да разделите тази операция. Цитирам ръководството тук:

Забележка:Текущата реализация на RETURN NEXT и RETURN QUERY съхранява целия набор от резултати, преди да се върне от функцията, както беше обсъдено по-горе. Това означава, че ако функцията PL/pgSQL произвежда много голям набор от резултати, производителността може да е лоша:данните ще бъдат записани на диск, за да се избегне изчерпване на паметта, но самата функция няма да се върне, докато не бъде генериран целият набор от резултати. Бъдеща версия на PL/pgSQL може да позволи на потребителите да дефинират функции за връщане на набор, които нямат това ограничение. Понастоящем точката, в която данните започват да се записват на диск, се контролира от променливата work_memconfiguration. Администраторите, които имат достатъчно памет, за да съхраняват по-големи набори от резултати в паметта, трябва да обмислят увеличаване на този параметър.

Помислете за изчисляване на редове за една система в даден момент или задайте достатъчно висока стойност за work_mem да се справят с натоварването. Следвайте връзката, предоставена в цитата за повече информация относно work_mem.

Един от начините е да зададете много висока стойност за work_mem с SET LOCAL във вашата функция, която е ефективна само за текущата транзакция. Добавих коментиран ред във функцията. Правне задайте го много високо в световен мащаб, тъй като това може да удари вашия сървър. Прочетете ръководството.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Не може да се свърже с postgres с помощта на jdbc в pyspark shell

  2. Не можа да се свърже със сървър на postgres в докер от докеризирано приложение

  3. Не мога да намеря клиентската библиотека на PostgreSQL (libpq)

  4. Изтрийте дублиращи се редове от малка таблица

  5. Готови ли сме за Nordic PPGDay?