2010-07-08 5 views
16

Veritabanları görünümünden veri alan (SQL Server 2005) raporlama için genel bir sistem kullanıyorum. Bu bakış açısıyla, veriyi bir satırda bir satırda birleştirmek zorunda kaldım ve priyanka.sarkar tarafından açıklanan çözümü bu iş parçacığında kullandım: Combine multiple results in a subquery into a single comma-separated value. Şimdi XML sqlxml -I ile (& =>& vs.) kodlanmış alır benim veriler dışındaSQLXML?

mükemmel çalışıyor
SELECT STUFF(
    ( SELECT ', ' + Name 
     FROM MyTable _in 
     WHERE _in.ID = _out.ID 
     FOR XML PATH('')),  -- Output multiple rows as one xml type value, 
            -- without xml tags 
    1, 2, '')  -- STUFF: Replace the comma at the beginning with empty string 
FROM MyTable _out 
GROUP BY ID  -- Removes duplicates 

(performansta ortaya bile ağır değil): Çözüm bilgiler (örneğin alt sorgu) birleştirilmesi için SQLXML kullanan Sonuçta XML verisini istemedim, bunu sadece bir numara olarak kullandım ve genel sistem yüzünden şifrelenmiş veriyi düzgün bir şekilde rapor edebilmek için bunu kodlayamam. CURSOR-birleştirme veya COALESCE-ing burada bir seçenek değil saklı yordamları kullanamazsınız. Bu nedenle, ben ... XML tekrar, veya daha da iyisi: SQLXML'in kodlamasını engeller. Açıkçası ben bunu yapar saklı bir fonksiyon yazabiliriz, ancak bir seçenek olarak type belirtirseniz ben ... Yardımlarınız için

Teşekkür ...

cevap

5

yerleşik bir, daha güvenli bir şekilde tercih ediyorum for xml, XML türünü varchar'a dönüştürmek için bir XPath sorgusu kullanabilirsiniz. bir örnek tablo değişkeni:

declare @MyTable table (id int, name varchar(50)) 

insert @MyTable (id, name) select 1, 'Joel & Jeff' 
union all select 1, '<<BIN LADEN>>' 
union all select 2, '&&BUSH&&' 

olası bir çözümdür:

select b.txt.query('root').value('.', 'varchar(max)') 
from (
     select distinct id 
     from @MyTable 
     ) a 
cross apply 
     (
      select CASE ROW_NUMBER() OVER(ORDER BY id) WHEN 1 THEN '' 
         ELSE ', ' END + name 
     from @MyTable 
     where id = a.id 
     order by 
       id 
     for xml path(''), root('root'), type 
     ) b(txt) 

Bu yazdırır:

Joel & Jeff, <<BIN LADEN>> 
&&BUSH&& 

İşte XML dönüşüm olmadan bir alternatiftir. Yinelemeli bir sorgusu var, bu nedenle performans kilometresi değişebilir. Bu Quassnoi's blog geliyor:

;WITH with_stats(id, name, rn, cnt) AS 
     (
     SELECT id, name, 
       ROW_NUMBER() OVER (PARTITION BY id ORDER BY name), 
       COUNT(*) OVER (PARTITION BY id) 
     FROM @MyTable 
     ), 
     with_concat (id, name, gc, rn, cnt) AS 
     (
     SELECT id, name, 
       CAST(name AS VARCHAR(MAX)), rn, cnt 
     FROM with_stats 
     WHERE rn = 1 
     UNION ALL 
     SELECT with_stats.id, with_stats.name, 
       CAST(with_concat.gc + ', ' + with_stats.name AS VARCHAR(MAX)), 
       with_stats.rn, with_stats.cnt 
     FROM with_concat 
     JOIN with_stats 
     ON  with_stats.id = with_concat.id 
       AND with_stats.rn = with_concat.rn + 1 
     ) 
SELECT id, gc 
FROM with_concat 
WHERE rn = cnt 
OPTION (MAXRECURSION 0) 
+7

Teşekkürler, ben " '.value(), TİP (. ' 'Nvarchar (max)') XML PATH (' İÇİN ... SEÇ)'" – Koen

+2

için basitleştirilmiş +1 Çapraz başvuru ve kök seçenekleri ile kafam karışmıştı, bu yüzden bir cevap olarak @ Koen'in yorumunu ekledim. – dotjoe

22
(
select ... 
from t 
for xml path(''), type 
).value('.', 'nvarchar(max)') 
+0

bu 'type' direktifi beni çok fazla zaman kazandı. – Sung