sobota, 20 listopada 2010

concat

Normalizacja, pierwsza postać normalna (1FN) sobie a życie czasami sobie.
Sposobów „dobierania” się do danych oddzielonych przecinkiem, średnikiem, spacją i innymi jest wiele, jednym z dobrych pomysłów jest użycie potęgi XML.
Mamy tabelę, przykładowo dane oddzieliłem przecinkiem ale może to być inny znak.

CREATE TABLE #test (id INT IDENTITY(1,1),tekst VARCHAR(255))
go

INSERT #test(tekst)
SELECT'jeden,dwa,trzy,cztery,pięć,sześć,siedem,osiem,dziewięć'
UNION ALL
SELECT'112,134,12345,1234,1789,234,28'

Rozwiązanie problemu

SELECT id,
      tx.parser.value('@element', 'varchar(100)')AS elementy
      FROM(SELECT id, 
            CONVERT(XML,'<rekord element="'
            + REPLACE(tekst,',','"/><rekord element="')+'"/>')
            AS parser
      FROM #test)AS t
CROSS APPLY t.parser.nodes('/rekord')AS tx (parser)


Dostajemy wynik

id          elementy
--------------------------
1           jeden
1           dwa
1           trzy
1           cztery
1           pięć
1           sześć
1           siedwm
1           osiem
1           dziewięć
2           112
2           134
2           12345
2           1234
2           1789
2           234
2           28
A teraz w drugą stronę
Zrobimy tabelę #test2

SELECT id,
      tx.parser.value('@element', 'varchar(100)')AS elementy
into #test2
      FROM(SELECT id, 
            CONVERT(XML,'<rekord element="'
            + REPLACE(tekst,',','"/><rekord element="')+'"/>')
            AS parser
      FROM #test)AS t
CROSS APPLY t.parser.nodes('/rekord')AS tx (parser)

SELECT * FROM #test2

id          elementy
----------- ----------
1           jeden
1           dwa
1           trzy
1           cztery
1           pięć
1           sześć
1           siedem
1           osiem
1           dziewięć
2           112
2           134
2           12345
2           1234
2           1789
2           234
2           28


Zapytnie

SELECT p1.id,
       ( SELECT  elementy + ','
           FROM #test2 p2
          WHERE p2.id = p1.id
          ORDER BY id          
          FOR XML PATH('') ) AS tekst
      FROM #test2 p1
      GROUP BY id

lub

SELECT DISTINCT id,tekst
    FROM #test2 p1
   CROSS APPLY ( SELECT elementy + ','
                     FROM #test2 p2
                     WHERE p2.id = p1.id
                     ORDER BY id
                     FOR XML PATH('') )  D ( tekst )

Wynik

id          tekst
----------------------------------------------------------------------
1           jeden,dwa,trzy,cztery,pięć,sześć,siedem,osiem,dziewięć,
2           112,134,12345,1234,1789,234,28,

1 komentarz:

  1. Ta metoda jest fajna w duecie z funkcją STUFF, dzięki której można łatwo pozbyć się pierwszego przecinka (ja zawsze zaczynam konkatenację od przecinka właśnie z tego powodu). Ale metoda ma też poważne ograniczenia - wystarczy, że trafi się nam jakiś znaczek kodowany jako specjalna encja w XMLu i dostaniemy krzaczki a la & :-)

    OdpowiedzUsuń