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

Stockage et interrogation de l'arborescence des intervalles dans PostgreSQL

Vous pouvez utiliser les types de données de plage et stocker chaque type disjoint dans une ligne.

Pour votre échantillon :

-- The table
CREATE TABLE sets(id text, range int4range);
-- Values of set A
INSERT INTO sets VALUES('A', '[1,1]'),('A','[7,7]'),('A','[9,13]');
-- Values of set B
INSERT INTO sets VALUES('B','[1,1]'),('B','[7,7]'),('B','[10,10]');

Pour vérifier si B est un sous-ensemble de A, vous pouvez joindre les deux avec tous les tuples dont la plage de A contient la plage de B :

 SELECT b.range
 FROM sets b JOIN sets a
     ON a.range @> b.range
 WHERE a.id='A' AND b.id='B'

Avec cela, vous pouvez vérifier si toutes les valeurs de l'ensemble B sont dans le résultat ci-dessus (ce qui signifie que toutes les plages de B sont contenues par au moins une plage de A) :

 SELECT NOT EXISTS(
     SELECT 1 FROM sets q WHERE q.id='B' AND q.range NOT IN (
         SELECT b.range
         FROM sets b JOIN sets a
             ON a.range @> b.range
         WHERE a.id='A' AND b.id='B'
     ));

Pour obtenir l'intersection, vous pouvez croiser les deux et exclure les vides :

 SELECT * FROM (
     SELECT a.range * b.range AS intersec
     FROM sets a CROSS JOIN sets b WHERE  a.id='A' AND b.id='B'
 ) i WHERE NOT isempty(i.intersec);

Un problème avec cette approche est que vous ne devez conserver que des plages disjointes à travers différents tuples. Par exemple, la plage [1,5] et [4,7] d'un ensemble doit résider dans un tuple avec [1,7] uniquement. Pour vous en assurer, vous pouvez les insérer dans une table temporaire (lors de l'insertion ou de la mise à jour), les croiser dans la table elle-même avec des tuples qui se chevauchent et les joindre et garder les autres tels qu'ils sont.