PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment regrouper les lignes suivantes par valeur non unique

Si votre cas est aussi simple que le suggèrent les exemples de valeurs, @Giorgos' answer sert bien.

Cependant, ce n'est généralement pas le cas . Si l'id la colonne est un serial , vous ne pouvez pas partir du principe qu'une ligne avec un time antérieur a également un id plus petit .
Aussi, time valeurs (ou timestamp comme vous l'avez probablement fait) peuvent facilement être des doublons, vous devez rendre l'ordre de tri sans ambiguïté.

En supposant que les deux peuvent se produire et que vous voulez le id à partir de la ligne avec la time la plus ancienne par tranche de temps (en fait, le plus petit id au plus tôt temps , il pourrait y avoir des égalités), cette requête traiterait correctement la situation :

SELECT *
FROM  (
   SELECT DISTINCT ON (way, grp)
          id, way, time AS time_from
        , max(time) OVER (PARTITION BY way, grp) AS time_to
   FROM (
      SELECT *
           , row_number() OVER (ORDER BY time, id)  -- id as tie breaker
           - row_number() OVER (PARTITION BY way ORDER BY time, id) AS grp
      FROM   table1
      ) t
   ORDER  BY way, grp, time, id
   ) sub
ORDER  BY time_from, id;
  • ORDER BY time, id être sans ambiguïté. En supposant que le temps n'est pas unique, ajoutez le (supposé unique) id pour éviter des résultats arbitraires - qui pourraient changer entre les requêtes de manière sournoise.

  • max(time) OVER (PARTITION BY way, grp) :sans ORDER BY , le cadre de la fenêtre s'étend sur toutes les lignes de la PARTITION, nous obtenons donc le maximum absolu par tranche de temps.

  • La couche de requête externe n'est nécessaire que pour produire l'ordre de tri souhaité dans le résultat, puisque nous sommes liés à un ORDER BY différent dans la sous-requête sub en utilisant DISTINCT ON . Détails :

SQL Fiddle démontrant le cas d'utilisation.

Si vous cherchez à optimiser les performances, une fonction plpgsql pourrait être plus rapide dans un tel cas. Réponse étroitement liée :

A part :n'utilisez pas le nom de type de base time comme identifiant (également un mot réservé en SQL standard ).