Você pode fazer isso usando consultas hierárquicas - aqui está uma usando o estilo antigo
connect by
:WITH your_table AS (SELECT 1 ID, 'AL' state FROM dual UNION ALL
SELECT 1 ID, 'AZ' state FROM dual UNION ALL
SELECT 1 ID, 'MI' state FROM dual UNION ALL
SELECT 2 ID, 'TX' state FROM dual UNION ALL
SELECT 2 ID, 'TN' state FROM dual UNION ALL
SELECT 2 ID, 'MO' state FROM dual UNION ALL
SELECT 2 ID, 'ND' state FROM dual UNION ALL
SELECT 3 ID, 'OH' state FROM dual)
SELECT ID,
state,
ltrim(SYS_CONNECT_BY_PATH(state, ','), ',') combinations,
LEVEL
FROM (SELECT id,
state,
count(*) OVER (PARTITION BY id) state_cnt
FROM your_table)
WHERE state_cnt = 1
OR (state_cnt > 1 AND LEVEL > 1)
CONNECT BY PRIOR ID = ID
AND PRIOR state < state
AND PRIOR sys_guid() IS NOT NULL;
ID STATE COMBINATIONS LEVEL
---------- ----- ------------ ----------
1 AZ AL,AZ 2
1 MI AL,AZ,MI 3
1 MI AL,MI 2
1 MI AZ,MI 2
2 TX TN,TX 2
2 TX MO,TX 2
2 TN MO,TN 2
2 TX MO,TN,TX 3
2 ND MO,ND 2
2 TX MO,ND,TX 3
2 TN MO,ND,TN 3
2 TX MO,ND,TN,TX 4
2 TX ND,TX 2
2 TN ND,TN 2
2 TX ND,TN,TX 3
3 OH OH 1
O
prior sys_guid() is not null
A condição na cláusula connect by é necessária para garantir que estamos fazendo um loop nas linhas corretas (se você a omitir, o resultado conterá muitas linhas extras). Excluí linhas com apenas um único estado na saída - exceto se o id listar apenas um único estado. Você pode ou não querer incluir estados únicos na saída; nesse caso, você pode remover os predicados completamente.