Trouver le 1er élément disponible dans une liste de numériques

On veut parfois trouver le 1er élément disponible dans une liste. C'est souvent le cas quand la clé primaire d'une table est un nombre mais qu'il n'est pas soumis à une séquence.. Ou alors qu'on a des trous dans la séquence et qu'on veut les combler.

Soit la table nombres (a integer, [...]), la requête suivante retourne le 1er élement disponible:

explain
SELECT (x.a+1) AS id_disponible
FROM nombres x
LEFT JOIN nombres y
ON ((x.a + 1) = y.a)
WHERE y.a IS NULL
ORDER BY x.a LIMIT 1;

QUERY PLAN
-----------------------------------------------------------------------------------
Limit (cost=0.00..1.58 rows=1 width=4)
-> Nested Loop Left Join (cost=0.00..22.09 rows=14 width=4)
Join Filter: (("outer".a + 1) = "inner".a)
Filter: ("inner".a IS NULL)
-> Index Scan using id_a on nombres x (cost=0.00..3.15 rows=14 width=4
-> Seq Scan on nombres y (cost=0.00..1.14 rows=14 width=4)
(6 lignes)

test2=> SELECT (x.a+1) AS id_disponible FROM nombres x LEFT JOIN nombres
y ON ((x.a + 1) = y.a) WHERE y.a IS NULL ORDER BY x.a LIMIT 1;
id_disponible
---------------
4
(1 ligne)

Si vous constatez des lenteurs, il vous faudra créer un index sur a (si ce n'est pas déjà fait, ce dont je doute):

create unique index id_a on nombres(a);

Et un index fonctionnel comme suit:

create index id_a_suivant on nombres ((a+1));

Merci à John Hansen (appeljack) pour cette idée.