2011-10-13 18 views
6

Sıklıkla şu sorguları kullanırım:XML ile birlikte satır birleştirmesi, ancak birden çok sütun ile?

SELECT * 
FROM ThisTable 
     OUTER APPLY (SELECT (SELECT SomeField + ' ' AS [data()] 
          FROM SomeTable 
          WHERE SomeTable.ID = ThisTable.ID 
          FOR XML PATH ('')) AS ConcatenatedSomeField) A 

Genellikle tek bir tablo yerine, bu tablodan birleştirilmiş birleştirilmiş birleştirilmiş alanlar almak istiyorum. Bunu mantıklı bir şekilde yapabilirim:

SELECT * 
FROM ThisTable 
     OUTER APPLY (SELECT (SELECT SomeField + ' ' AS [data()] 
          FROM SomeTable 
          WHERE SomeTable.ID = ThisTable.ID 
          FOR XML PATH ('')) AS ConcatenatedSomeField) A 
     OUTER APPLY (SELECT (SELECT SomeField2 + ' ' AS [data()] 
          FROM SomeTable 
          WHERE SomeTable.ID = ThisTable.ID 
          FOR XML PATH ('')) AS ConcatenatedSomeField2) B 
     OUTER APPLY (SELECT (SELECT SomeField3 + ' ' AS [data()] 
          FROM SomeTable 
          WHERE SomeTable.ID = ThisTable.ID 
          FOR XML PATH ('')) AS ConcatenatedSomeField3) C 

Ancak, herhangi bir şey güncellenmesi gerektiğinde berbat ve hataya eğilimli görünüyor; Ayrıca, SomeTable genellikle birleşik tabloların uzun bir listesidir, bu nedenle aynı tabloları tekrar tekrar elde etmek için performans sonuçları da olabilir.

Bunu yapmanın daha iyi bir yolu var mı?

Teşekkürler.

cevap

8

Böyle bir şey yapabilirsiniz. XML değerini bir dizeye hemen göndermek yerine, bu sorgu, sorgulanabilir bir xml türü nesneyi döndürmek için TYPE anahtar sözcüğünü kullanır. Üç sorgu işlevi, Somefield öğesinin tüm örnekleri için xml nesnesini arar ve yalnızca bu değerleri içeren yeni bir xml nesnesi döndürür. Sonra değer fonksiyon değerlerini çevreleyen xml etiketlerini çıkarır ve bir varchar içine geçer (maks)

SELECT ThisTable.ID 
     ,[A].query('/Somefield').value('/', 'varchar(max)') AS [SomeField_Combined] 
     ,[A].query('/Somefield2').value('/', 'varchar(max)') AS [SomeField2_Combined] 
     ,[A].query('/Somefield3').value('/', 'varchar(max)') AS [SomeField3_Combined] 
FROM ThisTable 
     OUTER APPLY (
        SELECT (
          SELECT SomeField + ' ' AS [SomeField] 
            ,SomeField2 + ' ' AS [SomeField2] 
            ,SomeField3 + ' ' AS [SomeField3] 
          FROM SomeTable 
          WHERE SomeTable.ID = ThisTable.ID 
          FOR 
          XML PATH('') 
           ,TYPE 
          ) AS [A] 
        ) [A] 
+0

Güzel bir fikir ama performans iyi değil http://dba.stackexchange.com/q/125771/3690 –

2

Bu Burada verdi aynı cevabı: https://dba.stackexchange.com/questions/125771/multiple-column-concatenation/

başvurulan söz konusu sorunun OP Burada verilen cevap. Aşağıda en basit cevabın en iyi olabileceğini görebilirsiniz. SomeTable birden fazla tablo ise, aynı karmaşık kodu birden çok kez kullanmaktan kaçınmak için devam edip bir CTE'ye koyardım.

6 milyondan fazla satır kullanarak birkaç sınama yürüttüm. Kimlik sütunundaki bir endeksle.

İşte ortaya çıktık.

Başlangıçtaki sorgusu:

SELECT * FROM (
    SELECT t.id, 
      stuff([M].query('/name').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined1], 
      stuff([M].query('/car').value('/', 'varchar(max)'),1,1,'') AS [SomeField_Combined2] 
    FROM dbo.test t 
    OUTER APPLY(SELECT (
        SELECT id, ','+name AS name 
        ,','+car AS car 
        FROM test WHERE test.id=t.id 
        FOR XML PATH('') ,type) 
       AS M) 
      M) S 
GROUP BY id, SomeField_Combined1, SomeField_Combined2 

Bu seferki ~ 23 dakika boyunca koştu.

İlk öğrendiğim sürüm olan bu sürümü çalıştırdım. Bazı yönlerden daha uzun sürmesi gerektiği gibi görünüyor ama değil.

SELECT test.id, 
    STUFF((SELECT ', ' + name 
      FROM test ThisTable 
      WHERE test.id = ThisTable.id 
      FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField, 
    STUFF((SELECT ', ' + car 
      FROM test ThisTable 
      WHERE test.id = ThisTable.id 
      FOR XML PATH ('')),1,2,'') AS ConcatenatedSomeField2 
FROM test 
GROUP BY id 

Bu sürüm yalnızca 2 dakika içinde gerçekleştirilmiştir.

İlgili konular