Как извлечь и объединить части XML в TSQL - PullRequest
0 голосов
/ 23 марта 2020

Я новичок ie в обработке T- SQL и XML на языке, я провел несколько дней, изучая и пытаясь понять все эти новые для меня концепции. Вопрос, который я собираюсь задать, может быть немного глупым, но я был бы признателен за любую помощь. У меня есть следующий XML документ, хранящийся в переменной с именем @tblCpSttgs_fldsPrmsMap

<row>
  <targetField>ano</targetField>
  <copyProcParamAssoc>@ipYear</copyProcParamAssoc>
  <fieldContInParam>0</fieldContInParam>
</row>
<row>
  <targetField>mes</targetField>
  <copyProcParamAssoc>@ipMonth</copyProcParamAssoc>
  <fieldContInParam>0</fieldContInParam>
</row>
<row>
  <targetField>id_expediente</targetField>
  <copyProcParamAssoc>@ipExps</copyProcParamAssoc>
  <fieldContInParam>1</fieldContInParam>
</row>

, которая является результатом следующего запроса

SET @tblCpSttgs = CURSOR FOR
SELECT tblcpsttgs.id, 
        tblcpsttgs.sourceTableDB, 
        tblcpsttgs.sourceTableSch, 
        tblcpsttgs.sourceTableName, 
        tblcpsttgs.targetLinkedServer, 
        tblcpsttgs.targetTableDB, 
        tblcpsttgs.targetTableSch, 
        tblcpsttgs.targetTableName, 
        tblcpsttgs.targetGroup, 
        tblcpsttgs.copyBehavior, 
        fieldsParamsMap = CONVERT(XML, (
            SELECT fldcpsttgs.targetField, fldcpsttgs.copyProcParamAssoc, fldcpsttgs.fieldContInParam
            FROM dbo.FieldCopySettings fldcpsttgs 
            WHERE fldcpsttgs.tableCopySettingsId = tblcpsttgs.id AND
                    fldcpsttgs.copyProcParamAssoc IS NOT NULL
            FOR XML PATH
        ))
FROM dbo.TableCopySettings tblcpsttgs
ORDER BY tblcpsttgs.copyOrder DESC;

OPEN @tblCpSttgs;

FETCH NEXT FROM @tblCpSttgs INTO @tblCpSttgs_id, @tblCpSttgs_srcTblDB, @tblCpSttgs_srcTblSch, @tblCpSttgs_srcTblNm, @tblCpSttgs_tgtLnkSrv, @tblCpSttgs_tgtTblDB, @tblCpSttgs_tgtTblSch, @tblCpSttgs_tgtTblNm, @tblCpSttgs_tgtGrp, @tblCpSttgs_cpBhr, @tblCpSttgs_fldsPrmsMap;

Так что в этой переменной я сохранил де XML на котором я хочу повторить. Что мне нужно, это объединить значения узлов, если выполняются определенные условия, и вернуть все объединенные в одном и том же тексте. Из того, что я понял в документации, которую я изучал, я сделал этот запрос

WITH fldsMap AS 
(
    SELECT 
        fldsMap.rows.query('for $i in targetField return $i').value('.', 'nvarchar(max)') AS targetField,
        fldsMap.rows.query('for $i in copyProcParamAssoc return $i').value('.', 'nvarchar(max)') AS copyProcParamAssoc,
        fldsMap.rows.query('for $i in fieldContInParam return $i').value('.', 'bit') AS fieldContInParam
    FROM 
        @tblCpSttgs_fldsPrmsMap.nodes('row') fldsMap (rows)
)
SELECT 
    (CASE 
        WHEN fldsMap.fieldContInParam = 1 
           THEN CONCAT('CONCAT('','', ISNULL(', fldsMap.copyProcParamAssoc, ', RTRIM(', fldsMap.targetField, ')), '','') LIKE CONCAT(''%,'', RTRIM(', fldsMap.targetField, '), '',%'')') 
           ELSE CONCAT(fldsMap.targetField, ' = ', fldsMap.copyProcParamAssoc) 
     END)
FROM fldsMap

, и я получил этот вывод

Query output

Но то, что мне действительно нужно, объединено в одном и том же выводе, что-то вроде этого

ano = @ipYear AND mes = @ipMonth 
    AND CONCAT(',', ISNULL(@ipExps, RTRIM(id_expediente)), ',') LIKE CONCAT('%,', RTRIM(id_expediente), ',%')

Как мне этого добиться?

1 Ответ

1 голос
/ 23 марта 2020
declare @x xml = N'<row>
  <targetField>ano</targetField>
  <copyProcParamAssoc>@ipYear</copyProcParamAssoc>
  <fieldContInParam>0</fieldContInParam>
</row>
<row>
  <targetField>mes</targetField>
  <copyProcParamAssoc>@ipMonth</copyProcParamAssoc>
  <fieldContInParam>0</fieldContInParam>
</row>
<row>
  <targetField>id_expediente</targetField>
  <copyProcParamAssoc>@ipExps</copyProcParamAssoc>
  <fieldContInParam>1</fieldContInParam>
</row>';


select 
stuff(
(
SELECT N' AND ' + 
    (CASE 
        WHEN fldsMap.fieldContInParam = 1 
           THEN CONCAT('CONCAT('','', ISNULL(', fldsMap.copyProcParamAssoc, ', RTRIM(', fldsMap.targetField, ')), '','') LIKE CONCAT(''%,'', RTRIM(', fldsMap.targetField, '), '',%'')') 
           ELSE CONCAT(fldsMap.targetField, ' = ', fldsMap.copyProcParamAssoc) 
     END) 
from     
(
select 
    r.row.value('targetField[1]', 'nvarchar(100)') as targetField,
    r.row.value('copyProcParamAssoc[1]', 'nvarchar(100)') as copyProcParamAssoc,
    r.row.value('fieldContInParam[1]', 'nvarchar(100)') as fieldContInParam     
from @x.nodes('/row') as r(row)
) as fldsMap
for xml path(''), type).value('.', 'nvarchar(max)'), 1, 5, N'');


SELECT 
string_agg( 
    (CASE 
        WHEN fldsMap.fieldContInParam = 1 
           THEN CONCAT('CONCAT('','', ISNULL(', fldsMap.copyProcParamAssoc, ', RTRIM(', fldsMap.targetField, ')), '','') LIKE CONCAT(''%,'', RTRIM(', fldsMap.targetField, '), '',%'')') 
           ELSE CONCAT(fldsMap.targetField, ' = ', fldsMap.copyProcParamAssoc) 
     END) , ' and ')
from     
(
select 
    r.row.value('targetField[1]', 'nvarchar(100)') as targetField,
    r.row.value('copyProcParamAssoc[1]', 'nvarchar(100)') as copyProcParamAssoc,
    r.row.value('fieldContInParam[1]', 'nvarchar(100)') as fieldContInParam     
from @x.nodes('/row') as r(row)
) as fldsMap;


select @x.query('
let $f := /row[1]
for $r in /row
    let $fieldContInParam := ($r/fieldContInParam/text())[1]
    let $copyProcParamAssoc := ($r/copyProcParamAssoc/text())[1]
    let $targetField := ($r/targetField/text())[1]
return 
    concat( if ($r is $f) then "" else "AND ", 
    if ($fieldContInParam = 1) then 
        concat("CONCAT('','', ISNULL(", $copyProcParamAssoc, ", RTRIM(", $targetField, ")), '','') LIKE CONCAT(''%,'', RTRIM(", $targetField, "), '',%'')") 
    else
        concat($targetField, "=", $copyProcParamAssoc)
    )
'
).value('.', 'nvarchar(max)');
...