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.