Sep 13 2010

Concatenarea sirurilor de caractere dintr-o coloana intr-o singura valoare

Categorie: Metodologie | OLTP | SQL Server | T-SQL | TutorialCatalin Dumitru @ 10:20

De multe ori avem nevoie sa concatenam mai multe valori text aflate pe coloana unui set de date, intr-o singura valoare, fie intr-o variabila fie ca si valoare a unei interogari. Spre exemplu, intr-o aplicatie de facturare se cere un raport cu lista facturilor dintr-o perioada iar intr-un camp numit description se cere lista produselor din fiecare factura. Pentru concatenarea mai multor valori intr-una singura exista mai multe metode explicate in scriptul demostrativ de mai jos:
- concatenare in variabila utilizand cod T-SQL sau functie scalara;
- concatenare in SELECT utilizand functie scalara;
- concatenare in SELECT fara functie utilizand operatorul CROSS APPLY sau subinterogare;

Cele 2 tabele utilizate "Scoala primara" si "Elevi" sunt prezentate mai jos iar un script de creare si populare se regasesc mai jos. 

 

 Rezultatele sunt prezentate mai jos. Mai trebuie mentionat ca aplicand algoritmul cu variabila, rezultatul final o sa contina o singura valoare, daca se doreste aplicarea la nivel de set de date, se poate aplica atat varianta cu aplicarea unei functii pentru fiecare rand al unui set de date cat si varianta "inline" - dinstr-un singur select. Varianta a 2-a are o performanta imbunatatita.

 

USE tempdb

GO
CREATE FUNCTION  FunctieConcatenare(@ID varchar(3))
RETURNS nvarchar(400) AS BEGIN
 DECLARE  @ListaElevi nvarchar(400)

 SELECT  @ListaElevi = ISNULL(@ListaElevi, '') + ', ' + Elev
 FROM  ScoalaPrimara sc
 INNER JOIN Elevi e
   ON sc.ID = e.ID_Clasa
 WHERE  sc.Clasa = @ID
 ORDER BY e.Elev

 RETURN  RIGHT(@ListaElevi, LEN(@ListaElevi) - 2)
END

GO
CREATE TABLE ScoalaPrimara (
    ID int PRIMARY KEY,
    Clasa varchar(3)
)
INSERT INTO  ScoalaPrimara(ID, Clasa)
SELECT   ID, Clasa
FROM (
  VALUES (1, 'I'),
    (2, 'II'),
    (3, 'III'),
    (4, 'IV')
) AS [Scoala primara](ID, Clasa)

CREATE TABLE Elevi (
    ID int primary key,
    ID_Clasa int,
    Elev nvarchar(20)

INSERT INTO  Elevi(ID, ID_Clasa, Elev)
SELECT   ID, ID_Clasa, Elev
FROM (
  VALUES (1, 1, N'Ionica'),
    (2, 1, N'Gigel'),
    (3, 1, N'Vasilica'),
    (4, 2, N'Dorel'),
    (5, 2, N'Cristinica'),
    (6, 3, N'Alexandra'),
    (7, 3, N'Georgel'),
    (8, 4, N'Mirciulica'),
    (9, 4, N'Simonica'),
    (10, 4, N'Bogdanel'),
    (11, 4, N'Petrica')
) AS Elevi(ID, ID_Clasa, Elev)

--CAZ 1: concatenare in variabila cu si fara functie
DECLARE   @ListaElevi nvarchar(400)

SELECT   @ListaElevi = ISNULL(@ListaElevi, '') + ', ' + Elev
FROM   ScoalaPrimara sc
INNER JOIN  Elevi e
  ON  sc.ID = e.ID_Clasa
WHERE   sc.Clasa = 'I'
ORDER BY  e.Elev

SELECT   RIGHT(@ListaElevi, LEN(@ListaElevi) - 2) AS [Lista elevi - variabila fara functie], dbo.FunctieConcatenare('I') AS [Lista elevi - variabila cu functie]

--CAZ 2: concatenare pe randuri folosind functie
SELECT   ID, Clasa, dbo.FunctieConcatenare(sp.Clasa) AS [Lista elevi - functie]
FROM   ScoalaPrimara sp

--CAZ 3: concatenare pe randuri fara variabila
--Folosind operatorul CROSS APPLY
SELECT   sp.ID, sp.Clasa, RIGHT(Lst.Elevi, LEN(Lst.Elevi) -2) AS [Lista elevi - CROSS APPLY]
FROM   ScoalaPrimara sp
CROSS APPLY  (
     SELECT  ', ' + e.Elev
     FROM  Elevi e
     WHERE  e.ID_Clasa = sp.ID
     ORDER BY Elev
     FOR XML PATH('')
) AS Lst(Elevi)
ORDER BY  sp.Clasa

 

--Folosind subinterogare
SELECT   ID, Clasa, RIGHT(Elevi, LEN(Elevi) -2) AS [Lista elevi - subinterogare]
FROM   (
    SELECT   ID, Clasa,
        (
         SELECT  ', ' + Elev
         FROM  Elevi e
         WHERE  e.ID_Clasa = sp.ID
         ORDER BY Elev
         FOR XML PATH('')
        ) AS Elevi
    FROM   ScoalaPrimara sp
) Lst
ORDER BY  Clasa

--clean up
DROP FUNCTION dbo.FunctieConcatenare
DROP TABLE  ScoalaPrimara
DROP TABLE  Elevi

Etichete: , , , ,