2013-08-16 2 views
0

임시 테이블의 채워지지 않은 필드 목록을 쉼표로 구분 된 문으로 가져 오려고하는 상황이 있습니다.테이블 또는 변수에 동적으로 작성된 'for xml'문 삽입

Field1  Field2 Field3 Field4 
'aaa'  null  ''  null 

그리고 매핑 : (실제 데이터 소스 테이블의 다수)에서 올로 (그리고 아마도 임시 테이블에 항상 하나의 행이 될 것입니다)

그래서 예제 데이터를 제공 나는만큼 멀리있어

Section UnansweredQs 
'Sec1' 'Q2' 
'Sec2' 'Q3, Q4' 

:

FieldName Question Section 
'Field1'  'Q1'  'Sec1' 
'Field2'  'Q2'  'Sec1' 
'Field3'  'Q3'  'Sec2' 
'Field4'  'Q4'  'Sec2' 

의 테이블은 내가 다음과 같은 결과를 싶습니다 을 통해 (나는

XML_F52E2B61-18A1-11d1-B105-00805F49916B 
---------------------------------------- 
q2, q3, q4 

을 얻을하지만 그 결과가 다른 테이블 또는 변수로 설정되지 수

create table #testData (f1 varchar(50), f2 int, f3 varchar(50), f4 varchar(50)) 
create table #qlist (fieldName varchar(5), question varchar(3), section varchar(5)) 

insert into #qlist values ('f1', 'q1', 'sec1'), ('f2', 'q2', 'sec1'), ('f3', 'q3', 'sec2'), ('f4', 'q4', 'sec2') 

insert into #testData values ('asda', null, '', null) 

그런

declare @usql nvarchar(max) = '' 
declare @sql nvarchar(max) 
declare @xml xml 

--build a gargantuan set of union statements, comparing the column value to null/'' and putting q# if it is 
set @usql = 
    (
    select 'select case when ' + c.name + ' is null or ' + c.Name + ' = '''' then ''' + q.question + ', '' else '''' end from #testData union ' 
    from tempdb..syscolumns c 
    inner join #qlist q 
     on c.name = q.fieldName 
    where c.id = object_id('tempdb..#testData') 
    for xml path('') 
    ); 
--remove the last 'union', append for xml path to pivot the rows into a single column of concatenated rows 
set @usql = left(@usql, len(@usql) - 6) + ' for xml path('''')' 

print @usql 

--remove final comma 
--get the position of the last comma in the select statment (ie after the final unanswered question) 
declare @lastComma int = charindex(',', reverse(@usql)) 
--add the bit before the last comma, and the bit after the last comma but skip the actual comma :) 
set @usql = left(@usql, len(@usql) - @lastComma) + right(@usql, @lastComma - 2) 

exec (@usql) 

을두고 : 쉼표 수행하여 질문의 목록을 분리 insert into #tmpresult exec (@usql) 접근법).

일반적으로 Msg 1086, Level 15, State 1, Line 1 The FOR XML clause is invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table syntax and apply FOR XML on top of it. 오류가 있습니다.

저는 여러 가지를 시도해 보았습니다. 랩핑, 노조 제거, CTE가 작동하지만 작동하지 않습니다.

답변

1

나는 당신을 위해 쿼리를 가지고 :

with cte as (
    select 
     N.Name 
    from Table1 
     cross apply (values 
      ('Field1', Field1), 
      ('Field2', Field2), 
      ('Field3', Field3), 
      ('Field4', Field4) 
     ) as N(Name,Value) 
    where N.Value is null or N.Value = '' 
) 
select distinct 
    T2.Section, 
    stuff(
     (
      select ', ' + TT.Question 
      from Table2 as TT 
       inner join cte as c on c.Name = TT.FieldName 
      where TT.Section = T2.Section 
      for xml path(''), type 
     ).value('.', 'nvarchar(max)') 
    , 1, 2, '') as UnansweredQs 
from Table2 as T2 

당신은 자신에 의해 동적으로 바꿀 수 있습니다 :이 작업을 수행하는 동적 SQL을 사용할 필요가 없습니다

sql fiddle demo

+0

덕분에, 정말 사용에 대한 자세한 내용은 필요 CTE의 : – cjb110

+0

실제로는 하위 쿼리와 함께이 작업을 수행하지만, 저 CTE 위해 훨씬 깨끗 수 있습니다 –

1

.

declare @X xml 

set @X = (
     select * 
     from #testData 
     for xml path('root'), elements xsinil, type 
     ) 

select section, 
     (
     select ', '+Q2.question 
     from #qlist as Q2 
     where Q1.section = Q2.section and 
      @X.exist('/root/*[local-name() = sql:column("Q2.fieldName")][. = ""]') = 1 
     for xml path(''), type 
     ).value('substring(text()[1], 2)', 'varchar(max)') as UnansweredQs 
from #qlist as Q1 
group by Q1.section 

SQL Fiddle