Oracle Tipps & Tricks: Kako rasparčati niz znakova [How to split a string]
Tuesday, 15.09.2009 – DejanUkoliko imate zadatak da rasparčate neki string (koristiću ovaj uvriježeni naziv umjesto prijevoda “niz znakova”), možete to obaviti na ovaj način.
Za tu svrhu moramo kreirati jednu funkciju, kojoj kao ulazni parametar predajemo string, a koja nam vraća array sa parčadima tog stringa:
CREATE OR REPLACE FUNCTION SplitString (pString IN VARCHAR2, pDelimiters IN VARCHAR2 ) RETURN DBMS_SQL.VARCHAR2S IS StringArray DBMS_SQL.VARCHAR2S; BEGIN WITH tblString AS (SELECT pString AS StringToSplit FROM dual) SELECT SUBSTR(StringToSplit, beg + 1, end_p - beg - 1) token BULK COLLECT INTO StringArray FROM (SELECT beg, lead(beg) OVER (ORDER BY beg) end_p, StringToSplit FROM (SELECT beg, StringToSplit FROM (SELECT LEVEL beg, StringToSplit FROM tblString CONNECT BY LEVEL <= LENGTH(StringToSplit) ) WHERE INSTR(pDelimiters ,SUBSTR(StringToSplit, beg, 1)) > 0 UNION ALL SELECT 0, StringToSplit FROM tblString UNION ALL SELECT LENGTH(StringToSplit) + 1, StringToSplit FROM tblString ) ) WHERE end_p IS NOT NULL AND end_p > beg + 1; RETURN StringArray; END; /
Primjer korištenja te funkcije izgleda ovako:
DECLARE laStringArray dbms_sql.varchar2s; lvString VARCHAR2(512) := 'Prvo;parce;dummy;teksta;a;ovo;je;parce;zadnje'; BEGIN laStringArray := SplitString(lvString,';'); -- ispisi zeljenu parcad pojedinacno: dbms_output.put_line('Prvo parce stringa: '|| laStringArray(1)); dbms_output.put_line('Zadnje parce stringa: '|| laStringArray(laStringArray.COUNT)); -- ili npr. svu parcad pomocu petlje: FOR i IN laStringArray.FIRST..laStringArray.LAST LOOP dbms_output.put_line('Parce br. '|| TO_CHAR(i) ||': '|| laStringArray(i)); END LOOP; END;
a rezultat izgleda ovako:
Prvo parce stringa: Prvo Zadnje parce stringa: zadnje Parce br. 1: Prvo Parce br. 2: parce Parce br. 3: dummy Parce br. 4: teksta Parce br. 5: a Parce br. 6: ovo Parce br. 7: je Parce br. 8: parce Parce br. 9: zadnje
Nadam se da će vam koristiti. 🙂
12 Responses to “Oracle Tipps & Tricks: Kako rasparčati niz znakova [How to split a string]”
za dejana i zidara.
molim vas ako možete odgovoriti na email.
hvala
By gusar on Sep 15, 2009
@gusar: ne znam na koji email mislis? Na koju adresu si slao?
By Dejan on Sep 15, 2009
Kakva slučajnost, upravo sam juče čitao na internetu o raznim implementacijama funkcija koje su zamjena za klasu StringTokenizer , tj. za razbijanje stringa na tokene…
By Darko on Sep 16, 2009
Dopuna mog prethodnog komentara:
“… implementacijama funkcija U PL/SQL-u koje su zamjena za JAVINU klasu StringTokenizer…”
By Darko on Sep 16, 2009
@Darko: I jesi nasao nesto korisno, sto bi se moglo iskoristiti u svakodnevnoj praksi?
By Dejan on Sep 16, 2009
Znas kako…
Radim jedan projekat u Javi trenutno, i radio sam nesto sa StringTokenizer-om , pa mi je samo palo na pamet da na brzinu vidim sta je zvanicno u PL/SQL-u najblize ovoj klasi…
Čisto, da znam za neka buduća vremena…
Google mi je dao par rezultata, i tu se iskljucivo radilo o ličnim rjesenjima nekih ljudi, kao npr. sto je ovo tvoje.
Kako nisam našao od prve ništa što je zvanično, vratio sam se svojim obavezama…
Ne kažem da nema, ja jednostavno nisam dalje tragao.
By Darko on Sep 16, 2009
@dejan
slao sam na email adresu koju imate baze-podataka.
u vezi oacle certifikata.
By Gusar on Sep 17, 2009
@gusar: Ja sam odgovorio na ihahaj emailova u vezi Oracle certifikata, tako da ne znam na koji tacno mislis … sa koje email adrese si slao, da pogledam imam li u inboxu ista i jesam li ti vec odgovorio?
@Darko: Dosta takvih slucajeva sam imao, gdje PL/SQL nema neke built-in funkcije, koje ima npr. Java … Evo danas mi se javio jedan PL/SQL programer i pita:”Koju proceduru u PL/SQL mogu koristiti, da saznam ime aktuelne caller procedure, kao npr. u javi this.name ili self.name?”
Nazalost sam mu morao odgovoriti, da PL/SQL tako nesto nema, ali sam ja napisao licno rjesenje i za to, koristeci kombinaciju OWA_UTIL.who_called_me i jos jedne pomocne procedure…
By Dejan on Sep 17, 2009
Eto onda sjajne ideje za zapocinjanje jednog open-source projekta 😉
By Darko on Sep 17, 2009
Evo pre pet minuta je na eliteSecurity neko pitao kako da napravi string od izabranih rekorda. Jedan od odgovora ukazao je na sajt http://www.projectdmx.com/tsql/sqlarrays.aspx
Tamo sam u poglavlju “Faking Arrays in SQL” koje se bavi tokenizacijom stringova (string parsing) nasao ovo:
Ako imamo tabelu brojeva od 1 do N, onda je mozemo upotrebiti za parsiranje stringova. Jedan nacin da se napravi tabela brojeva, Nbrs (n int) jeste ovo:
IF OBJECT_ID(‘dbo.Nbrs’) IS NOT NULL DROP TABLE dbo.Nbrs
;WITH Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 )
SELECT n
INTO dbo.Nbrs
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs ) D ( n )
WHERE n <= 500 ;
GO
Onda dalje moze da se uradi ovako nesto:
— String parsing:
DECLARE @p VARCHAR(50)
SET @p = ‘2,4,6,8,10,12,14,16’;
;
— String parsing:
DECLARE @p VARCHAR(50)
SET @p = ‘2,4,6,8,10,12,14,16’;
;
SELECT SUBSTRING( ‘,’ + @p + ‘,’, n + 1,
CHARINDEX( ‘,’, ‘,’ + @p + ‘,’, n + 1 ) – n – 1 ) AS “value”
FROM Nbrs
WHERE SUBSTRING( ‘,’ + @p + ‘,’, n, 1 ) = ‘,’
AND n < LEN( ‘,’ + @p + ‘,’ ) ;
Mozda moze i u ORACLE nesto ovako relativno kratko da se napise? Ne tvrdim da je jednostavno, kod sam naprosto kopirao sa sajta i proverio da li radi, i stvarno – radi.
Onda sam hteo da to naravno primenim na zivu tabelu, jednu iz AdventureWorks, i posto sam majstor, ja znam da pisem in-line SQL, nadosao sam na ovo (radi, provereno):
DECLARE @p VARCHAR(50)
SET @p = ‘2,4,6,8,10,12,14,16’;
;
SELECT ContactID
,FirstName
,LastName
FROM Person.Contact
WHERE ContactID IN
(SELECT Substring(‘,’ + @p
+ ‘,’,n + 1,Charindex(‘,’,’,’ + @p + ‘,’,n + 1) – n – 1) AS “value”
FROM dbo.Nbrs
WHERE Substring(‘,’ + @p + ‘,’,n,1) = ‘,’
AND n 0 ;
Ispada da ako proceduri posaljemo string @p, mozemo bez upotrebe korisnickih funkcija i bez komplikovanih in-line kverija da dobijemo rekorde iz tabele na osnovu liste koju smo poslali kao parametar.
Ovim je potvrdjeno pravilo da nazovi majstori (Zidar) mnog komplikuju, a pravi majstori (ko god je napisao originalni kod) znaju znanje 🙂
By Zidar on Sep 18, 2009
E, ponovo sam izgubio parce teksta. Treba ovako da se zavrsi tekst, posle resenja sa Adventure Works, treba da kaze:
Citajuci dalje tekst, shvatio sam da mi in-line query nije ni bio potreban i da cel stvar moze da se napise i ovako, direktno:
DECLARE @p VARCHAR(50)
SET @p = ‘2,4,6,8,10,12,14,16’;
SELECT ContactID, FirstName, LastName
FROM Person.Contact
WHERE CHARINDEX( ‘,’ + CAST(ContactID AS varchar) + ‘,’, ‘,’ + @p + ‘,’ ) > 0 ;
Ispada da ako proceduri posaljemo string @p, mozemo bez upotrebe korisnickih funkcija i bez komplikovanih in-line kverija da dobijemo rekorde iz tabele na osnovu liste koju smo poslali kao parametar.
Ovim je potvrdjeno pravilo da nazovi majstori (Zidar) mnogo i bespotrebno komplikuju, a pravi majstori (ko god je napisao originalni kod) znaju znanje 🙂
By Zidar on Sep 18, 2009
Kako se edituje coment posle submit? Dodao bih nesto
Jos jedno mesto gde se na temu tokenizovanaj stringova ima sta procitati (za SQL server doduse, ali SQL je SQL bar donekle…)
http://www.sommarskog.se/arrays-in-sql-2005.html#XML
I tu naravno nadjem da metod koji sam ponosno predstavio u komentaru spada u grupu ‘veoma spori i slabo efikasni metodi’. Nista ipak bez UDF.
🙂
By Zidar on Sep 18, 2009