El problema con Postgresql es que, primero, no admite tener grupos de captura dentro de sus aserciones anticipadas. Dicho esto, todos los grupos de captura dentro de una anticipación se tratarán como grupos que no son de captura ((?: ... )
), énfasis mío:
Entonces, incluso si PostgreSQL admitiera tener referencias inversas dentro de una búsqueda anticipada, aún no funcionaría como se esperaba debido a la restricción anterior (sin un grupo de captura, no puede tener una referencia inversa).
Una posible solución (lamentablemente será larga para requisitos complejos) sería contar el número de cada carácter:
WHERE
LENGTH(REGEXP_REPLACE(name, '[^a]+', '', 'g')) < 2 AND
LENGTH(REGEXP_REPLACE(name, '[^c]+', '', 'g')) < 2 AND
LENGTH(REGEXP_REPLACE(name, '[^e]+', '', 'g')) < 2 AND
LENGTH(REGEXP_REPLACE(name, '[^g]+', '', 'g')) < 2 AND
LENGTH(REGEXP_REPLACE(name, '[^i]+', '', 'g')) < 3 AND
LENGTH(REGEXP_REPLACE(name, '[acegi]+', '', 'g')) = 0;
[condición tomada y modificada de esta respuesta ; la última fila es para asegurarse de que solo haya esos caracteres en la cadena]