sql >> Database >  >> RDS >> PostgreSQL

Geordend aantal opeenvolgende herhalingen / duplicaten

Testcase

Ten eerste een handigere manier om uw gegevens te presenteren - of nog beter, in een sqlfiddle , klaar om mee te spelen:

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);

Vereenvoudigde zoekopdracht

Aangezien het onduidelijk blijft, neem ik alleen het bovenstaande aan als gegeven.
Vervolgens heb ik uw vraag vereenvoudigd om te komen tot:

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;

Hoewel het allemaal mooi en glanzend is om pure SQL te gebruiken, zal dit veel zijn sneller met een plpgsql-functie, omdat het dit kan doen in een enkele tabelscan waarbij deze query ten minste drie scans nodig heeft.

Sneller met plpgsql-functie:

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$;

Bel:

SELECT * FROM x.f_repeat_ct();

Zorg ervoor dat u uw kolomnamen altijd in tabellen kwalificeert in dit soort plpgsql-functie, omdat we dezelfde namen gebruiken als uitvoerparameters die voorrang zouden hebben als ze niet gekwalificeerd waren.

Miljarden rijen

Als u miljarden . heeft rijen , wilt u deze bewerking misschien opsplitsen. Ik citeer hier de handleiding:

Opmerking:de huidige implementatie van RETURN NEXT en RETURN QUERY slaat de volledige resultatenset op voordat u terugkeert van de functie, zoals hierboven besproken. Dat betekent dat als een PL/pgSQL-functie een zeer grote resultatenset produceert, de prestaties mogelijk slecht zijn:gegevens worden naar schijf geschreven om geheugenuitputting te voorkomen, maar de functie zelf zal pas terugkeren als de volledige resultatenset is gegenereerd. Een toekomstige versie van PL/pgSQL zou gebruikers in staat kunnen stellen om set-returning-functies te definiëren die deze beperking niet hebben. Momenteel wordt het punt waarop gegevens naar schijf worden geschreven, bepaald door de variabele work_memconfiguration. Beheerders die voldoende geheugen hebben om grotere resultatensets in het geheugen op te slaan, moeten overwegen deze parameter te verhogen.

Overweeg om rijen voor één systeem tegelijk te berekenen of een voldoende hoge waarde in te stellen voor work_mem om met de last om te gaan. Volg de link in de offerte voor meer informatie over work_mem.

Een manier zou zijn om een ​​zeer hoge waarde in te stellen voor work_mem met SET LOCAL in uw functie, die alleen van kracht is voor de huidige transactie. Ik heb een commentaarregel toegevoegd aan de functie. Doe niet zet het wereldwijd erg hoog, omdat dit je server kan vernietigen. Lees de handleiding.




  1. MySQL Galera-clusterreplicatie gebruiken om een ​​geo-gedistribueerde cluster te maken:deel één

  2. SQLAlchemy OP DUPLICATE KEY UPDATE

  3. Word lid van 3 tabellen in SQL

  4. Gegevens exporteren van SQL Server naar Excel en tekstbestand via het gebruik van SSIS-pakket