FOR XML: условные пустые узлы - PullRequest
0 голосов
/ 08 ноября 2019

Есть запрос SQL:

WITH q1 AS (
    SELECT 1 AS c1, 2 AS c2, 'three' AS c3, 'orange' AS row_type
    UNION ALL SELECT 11, 22, 'thirty three', 'banana'
    UNION ALL SELECT 111, 222, 'three hundred thirty three', 'apple'
) SELECT q1.c1
       , q1.c2
       , q1.c3
       , q1.row_type FROM q1 FOR XML PATH('row'),ROOT('doc'),type

Возвращает:

<doc>
  <row>
    <c1>1</c1>
    <c2>2</c2>
    <c3>three</c3>
    <row_type>orange</row_type>
  </row>
  <row>
    <c1>11</c1>
    <c2>22</c2>
    <c3>thirty three</c3>
    <row_type>banana</row_type>
  </row>
  <row>
    <c1>111</c1>
    <c2>222</c2>
    <c3>three hundred thirty three</c3>
    <row_type>apple</row_type>
  </row>
</doc>

Мне нужно вернуть:

<doc>
  <row>
    <c1>1</c1>
    <c2>2</c2>
    <c3>three</c3>
    <row_type>
        <orange />
    </row_type>
  </row>
  <row>
    <c1>11</c1>
    <c2>22</c2>
    <c3>thirty three</c3>
    <row_type>
        <banana />
    </row_type>
  </row>
  <row>
    <c1>111</c1>
    <c2>222</c2>
    <c3>three hundred thirty three</c3>
    <row_type>
        <apple />
    </row_type>
  </row>
</doc>

Т.е. я хочу создатьусловный пустой узел для каждого <row>, имя узла которого выводится из другого атрибута текущей записи.

Любые подсказки, как к этому подойти?

SQL Server 2012.

1 Ответ

4 голосов
/ 08 ноября 2019

Общий ответ: Не надо!

Всегда очень плохая идея, чтобы имя элемента было data. Намного лучше было бы

<row_type type="apple" />

Но вы могли бы как-то обмануть это одним из следующих способов:

- Этот запрос работает, когда вы заранее знаете все необходимые значения.
--Theмагия заключается в том, что XML по умолчанию пропускает значения NULL

WITH q1 AS (
    SELECT 1 AS c1, 2 AS c2, 'three' AS c3, 'orange' AS row_type
    UNION ALL SELECT 11, 22, 'thirty three', 'banana'
    UNION ALL SELECT 111, 222, 'three hundred thirty three', 'apple'
) 
SELECT q1.c1
     , q1.c2
     , q1.c3
     , CASE WHEN q1.row_type='orange' THEN '' END AS [row_type/orange] 
     , CASE WHEN q1.row_type='banana' THEN '' END AS [row_type/banana] 
     , CASE WHEN q1.row_type='apple' THEN '' END AS [row_type/apple] 
FROM q1 
FOR XML PATH('row'),ROOT('doc'),type;

- в этом запросе используется некоторая конкатенация строк и CAST

WITH q1 AS (
    SELECT 1 AS c1, 2 AS c2, 'three' AS c3, 'orange' AS row_type
    UNION ALL SELECT 11, 22, 'thirty three', 'banana'
    UNION ALL SELECT 111, 222, 'three hundred thirty three', 'apple'
) 
SELECT q1.c1
     , q1.c2
     , q1.c3
     --careful, if your "row_type" might not be a valid element name
     , CAST(CONCAT('<',q1.row_type,'/>') AS XML) AS [row_type] 
FROM q1 
FOR XML PATH('row'),ROOT('doc'),type;
...