Oracle Tipps & Tricks: Kako da spojim zapise (rekorde) u jedan string? [How to make a string out of records?]
Monday, 21.09.2009 – DejanU ovom članku ću napisati rješenje za problem – kako spojiti više zapisa u jedan string.
Kao primjer ću uzeti jedan “real world case”, kojeg i ja lično imam u svakodnevnoj praksi.
Naime, imam tabelu, koja sadrži popis aplikacija i podatke o osobama, koje rade na toj aplikaciji. Kada nešto mijenjam u bazi, moram putem E-Maila obavijestiti sve osobe zadužene za određenu aplikaciju. Naravno da bih mogao napisati jednu petlju i pomoću UTL_MAIL slati pojedinačno E-Mail svakome, ali sam za ovu, a i druge svrhe, odlučio napisati funkciju, koja mi vraća selektovane zapise (u ovom slučaju ime, prezime i E-Mail adresu) spojene u jedan string.
Potrebno je najprije kreirati uskladištenu proceduru ili funkciju, koja prima dva parametra (REF CURSOR i delimiter), a kao rezultat vraća “zaljepljeni” string, tj. sve selektovane zapise spojene u jedan string.
CREATE OR REPLACE FUNCTION sfJoinRecords
(
pCursor IN sys_refcursor,
pDelimiter IN VARCHAR2 := ','
) RETURN VARCHAR2
IS
lvTempValue VARCHAR2(32767);
lvReturnValue VARCHAR2(32767);
BEGIN
LOOP
FETCH pCursor INTO lvTempValue;
EXIT WHEN pCursor%NOTFOUND;
IF lvReturnValue IS NOT NULL THEN
lvReturnValue := lvReturnValue || pDelimiter;
END IF;
lvReturnValue := lvReturnValue || lvTempValue;
END LOOP;
CLOSE pCursor;
RETURN lvReturnValue;
END sfJoinRecords;
/
Korištenje ove funkcije izgleda ovako:
SELECT ap.first_name,
ap.last_name,
ap.email_address
FROM tb_apps_persons ap
WHERE ap.app_id = 8
AND ap.email_address IS NOT NULL;
FIRST_NAME LAST_NAME EMAIL_ADDRESS ---------- ---------- ----------------------------------- Pero Peric pero.peric@bazepodataka.net Marko Markovic marko.markovic@bazepodataka.net Laza Lazic laza.lazic@bazepodataka.net
SELECT DISTINCT
ap.first_name ||' '||
ap.last_name ||' <' ||
ap.email_address ||'>'
as persons
FROM tb_apps_persons ap
WHERE ap.app_id = 8
AND ap.email_address IS NOT NULL;
PERSONS -------------------------------------------------- Laza Lazic <laza.lazic@bazepodataka.net> Pero Peric <pero.peric@bazepodataka.net> Marko Markovic <marko.markovic@bazepodataka.net>
SELECT sfJoinRecords(
CURSOR(
SELECT DISTINCT
ap.first_name ||' '||
ap.last_name ||' <' ||
ap.email_address ||'>'
FROM tb_apps_persons ap
WHERE ap.app_id = 8
AND ap.email_address IS NOT NULL),
',') as persons
FROM dual;
PERSONS ------------------------------------------------------------------------------------------------------------------- Laza Lazic <laza.lazic@bazepodataka.net>,Pero Peric <pero.peric@bazepodataka.net>,Marko Markovic <marko.markovic@bazepodataka.net>
Naravno da se ova funkcija može koristiti za bezbroj drugih stvari, pa ako ju budete koristili u praksi, napišite u komentaru za šta ju koristite, kako bi i drugi dobili ideju ili iskoristili tu metodu.
Još jedna veoma bitna napomena: ukoliko funkciju koristite u kompleksnijim DML upitima u sklopu nekog paketa, onda ćete vjerovatno morati u specifikaciju paketa (package header) dodati ovo ograničenje:
PRAGMA RESTRICT_REFERENCES(sfJoinRecords, WNDS);
Objašnjenje za WNDS: “Asserts that the subprogram writes no database state (does not modify database tables).”
2 Responses to “Oracle Tipps & Tricks: Kako da spojim zapise (rekorde) u jedan string? [How to make a string out of records?]”
Možda može nešto ovako da pomogne takođe.
http://download.oracle.com/docs/cd/E11882_01/server.112/e10592/functions087.htm
To je nova funkcija u 11g, a inače je preuzeta od Tom Kyte-a koji je nešto slično objavio na asktom. Mislim da bi trebalo da vrati isti rezultat, ovako od oka gledano — nemam ovde na poslu 11g, kad odem kući probaću.
By simma on Oct 12, 2009
Ova funkcija LISTAGG je interesantna, vjerujem da cu ju moci iskoristiti u praksi 🙂
Samo jos da predjemo na verziju 11g hehehe … trenutno cekamo da izadje 11g Release 2 za Windows platformu, pa cemo onda da se aktivnije bacimo na izucavanje svih 11g djidja-midja 😀
By Dejan on Oct 12, 2009