Você pode usar os tipos de dados de intervalo e armazenar cada tipo disjunto em uma linha.
Para sua amostra:
-- 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]');
Para verificar se B é um subconjunto de A, você pode juntar ambos com todas as tuplas que o intervalo de A contém o intervalo de B:
SELECT b.range
FROM sets b JOIN sets a
ON a.range @> b.range
WHERE a.id='A' AND b.id='B'
Com isso, você pode verificar se todos os valores do conjunto B estão no resultado acima (o que significa que todos os intervalos de B estão contidos em pelo menos um intervalo 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'
));
Para obter a interseção, você pode cruzar as duas e excluir as vazias:
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);
Um problema sobre essa abordagem é que você deve manter apenas intervalos disjuntos em diferentes tuplas. Por exemplo, o intervalo [1,5] e [4,7] de um conjunto deve residir em uma tupla apenas com [1,7]. Para ter certeza disso, você pode inseri-los em uma tabela temporária (durante a inserção ou atualização), eles cruzam a própria tabela com tuplas que se sobrepõem e eles unem essas e mantêm as outras do jeito que estão.