Oracle Tipps & Tricks: Kako rasparčati niz znakova [How to split a string]

Tuesday, 15.09.2009 – Dejan

Ukoliko 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. 🙂

  1. 12 Responses to “Oracle Tipps & Tricks: Kako rasparčati niz znakova [How to split a string]”

  2. za dejana i zidara.

    molim vas ako možete odgovoriti na email.

    hvala

    By gusar on Sep 15, 2009

  3. @gusar: ne znam na koji email mislis? Na koju adresu si slao?

    By Dejan on Sep 15, 2009

  4. 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

  5. Dopuna mog prethodnog komentara:

    “… implementacijama funkcija U PL/SQL-u koje su zamjena za JAVINU klasu StringTokenizer…”

    By Darko on Sep 16, 2009

  6. @Darko: I jesi nasao nesto korisno, sto bi se moglo iskoristiti u svakodnevnoj praksi?

    By Dejan on Sep 16, 2009

  7. 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

  8. @dejan

    slao sam na email adresu koju imate baze-podataka.

    u vezi oacle certifikata.

    By Gusar on Sep 17, 2009

  9. @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

  10. Eto onda sjajne ideje za zapocinjanje jednog open-source projekta 😉

    By Darko on Sep 17, 2009

  11. 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

  12. 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

  13. 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

Post a Comment