Oto rozwiązanie, które wykorzystuje tylko standardowe funkcje tekstowe (zamiast wyrażeń regularnych) - co w większości przypadków powinno skutkować szybszym wykonaniem; usuwa 3 tylko wtedy, gdy jest to pierwszy znak poprzedzony przecinkiem, ostatni znak poprzedzony przecinkiem lub poprzedzony i poprzedzony przecinkiem oraz usuwa przecinek, który poprzedza go w środkowych literach i usuwa przecinek następujący po nim w pierwszy i trzeci przypadek.
Jest w stanie usunąć dwie trójki z rzędu (czego niektóre inne oferowane rozwiązania nie są w stanie zrobić), pozostawiając w miejscu kolejne przecinki (które prawdopodobnie zastępują NULL) i nie przeszkadzać liczbom takim jak 38 lub 123.
Strategia polega na tym, aby najpierw podwoić każdy przecinek (zastąp ,
z ,,
) oraz dołącz i dołącz przecinek (na początku i na końcu ciągu). Następnie usuń każde wystąpienie ,3,
. Od tego, co zostało, zastąp każdy ,,
z powrotem jednym ,
i na koniec usuń początkowy i końcowy ,
.
with
test_data ( str ) as (
select '1,2,3,4,5' from dual union all
select '1,2,3,3,4,4,5' from dual union all
select '12,34,5' from dual union all
select '1,,,3,3,3,4' from dual
)
select str,
trim(both ',' from
replace( replace(',' || replace(str, ',', ',,') || ',', ',3,'), ',,', ',')
) as new_str
from test_data
;
STR NEW_STR
------------- ----------
1,2,3,4,5 1,2,4,5
1,2,3,3,4,4,5 1,2,4,4,5
12,34,5 12,34,5
1,,,3,3,3,4 1,,,4
4 rows selected.
Uwaga Jak wskazano w MT0 (patrz Komentarze poniżej), spowoduje to zbyt duże przycięcie, jeśli oryginalny ciąg zaczyna się lub kończy przecinkami. Aby objąć ten przypadek, zamiast zawijać wszystko w trim(both ',' from ...)
Powinienem owinąć resztę w podzapytanie i użyć czegoś takiego jak substr(new_str, 2, length(new_str) - 2)
w zewnętrznym zapytaniu.