2010-07-08 2 views
16

데이터베이스보기 (SQL Server 2005)에서 데이터를 가져 오는보고를 위해 일반 시스템을 사용하고 있습니다. 이보기에서 나는 일대 다 관계의 데이터를 한 행에 병합해야하고이 스레드에 priyanka.sarkar에 의해 설명 된 솔루션을 사용했습니다 : Combine multiple results in a subquery into a single comma-separated value. 이제 XML이 SQLXML -I로 (& =>& 등)을 인코딩 얻을 내 데이터를 제외하고XML 인코딩이없는 SQLXML?

완벽하게 작동
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 

(가 성능 심지어 무거운 아니다) :이 솔루션은 데이터를 (하위 쿼리)을 병합 SQLXML을 사용 결국 XML 데이터를 원하지 않았고 방금 트릭으로 사용했습니다. 일반 시스템 때문에이 코드를 정리하여 코드화 된 데이터가 곧바로 보고서로 전달 될 수는 없습니다. CURSOR-merge 또는 COALESCE-ing은 여기에 옵션이 없기 때문에 스토어드 프로 시저를 일반 시스템과 함께 사용할 수 없습니다 ...

그래서 내가 찾고있는 것은 T-SQL에서 디코딩 할 수있는 방식입니다. XML을 다시 또는 그 이상 : SQLXML에서 인코딩하지 못하도록합니다. 물론 나는이 작업을 수행 저장 기능을 쓸 수 있지만, 당신은에 옵션으로 type을 지정하면 나는 ... 당신의 도움을

감사합니다 ...

답변

5

을 내장, 더 안전한 방법을 선호하는 것 for xml이면 XPath 쿼리를 사용하여 XML 형식을 varchar으로 다시 변환 할 수 있습니다. 예를 들어 테이블 변수가 :

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&&' 

한 가지 가능한 솔루션입니다 :

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) 

이 인쇄됩니다

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

다음은 XML 변환없이 대안입니다. 재귀 쿼리가 있기 때문에 성능 마일리지가 다를 수 있습니다. 그것은 Quassnoi's blog 출신 :

;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

감사합니다, 나는 " '.value(), TYPE (.', 'NVARCHAR (최대)')의 XML PATH ('SELECT ...)'" – Koen

+2

단순화 +1 교차 적용과 루트 옵션에 혼란스러워서 @ Koen의 설명을 답으로 추가했습니다. – dotjoe

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

이'type' 지시자는 많은 시간을 절약 해주었습니다. – Sung