У меня есть таблица, в которой сохраняются данные xml. Xml выглядит следующим образом

<responses>
  <response>
    <id>UniqueRowID</id>
    <value>16</value>
  </response>
  <response>
    <id>Language</id>
    <value>en-GB</value>
  </response>
  <response>
    <id>UserId</id>
    <value>21</value>
  </response>
</responses>

В следующем столбце могут быть другие данные. id и значение общие для всех. Но некоторые идентификаторы в одном ряду могут не быть в другом.

Теперь мне нужна таблица в следующем формате. Я знаю, что должны показывать все столбцы. Если какой-либо столбец отсутствует в xml, он может быть пустым. Как я могу этого добиться?

UniqueRowID Language UserId

--- ------- ------

16 en-ГБ 21

Я видел нечто подобное, но у меня ничего не работает, так как xml имеет другой способ представления в этих примерах

0
Binesh Nambiar C 2 Май 2016 в 20:36

3 ответа

Лучший ответ

Я ставлю это как второй ответ, так как это совершенно другой подход. С помощью этого кода вы можете прочитать любой XML этой структуры. Использование динамического SQL позволяет создавать имена динамических столбцов:

CREATE TABLE #tmpTbl (YourXml XML);
INSERT INTO #tmpTbl VALUES
('<responses>
  <response>
    <id>UniqueRowID</id>
    <value>16</value>
  </response>
  <response>
    <id>Language</id>
    <value>en-GB</value>
  </response>
  <response>
    <id>UserId</id>
    <value>21</value>
  </response>
    <response>
    <id>SomeOther1</id>
    <value>SO1</value>
  </response>
    <response>
    <id>SomeOther2</id>
    <value>SO2</value>
  </response>
</responses>');

DECLARE @columnNames VARCHAR(MAX)=
(
    STUFF(
    (
        SELECT ',[' + B.value('id[1]','varchar(max)')+ ']'
        FROM #tmpTbl
        CROSS APPLY YourXml.nodes('/responses/response') AS A(B)
        FOR XML PATH('')
    ),1,1,''    
    )
);

DECLARE @cmd VARCHAR(MAX)=
'SELECT p.*
FROM
(
    SELECT B.value(''id[1]'',''varchar(max)'') AS ColumnName
          ,B.value(''value[1]'',''varchar(max)'') AS ColumnValue
    FROM #tmpTbl
        CROSS APPLY YourXml.nodes(''/responses/response'') AS A(B)
) AS tbl
PIVOT
(
    MIN(ColumnValue) FOR ColumnName IN(' +  @columnNames + ')
) As p';

EXEC(@cmd);
GO

DROP TABLE #tmpTbl;

Результат:

UniqueRowID Language    UserId  SomeOther1  SomeOther2
16          en-GB       21      SO1         SO2
1
Shnugo 3 Май 2016 в 08:29

Попробуйте так:

DECLARE @xml XML=
'<responses>
  <response>
    <id>UniqueRowID</id>
    <value>16</value>
  </response>
  <response>
    <id>Language</id>
    <value>en-GB</value>
  </response>
  <response>
    <id>UserId</id>
    <value>21</value>
  </response>
</responses>'

SELECT @xml.value('(/responses/response[id="UniqueRowID"]/value)[1]','int') AS UniqueRowID
      , @xml.value('(/responses/response[id="Language"]/value)[1]','varchar(max)') AS Language
      , @xml.value('(/responses/response[id="UserId"]/value)[1]','int') AS UserId

Результат

UniqueRowID Language    UserId
16          en-GB       21
1
Shnugo 3 Май 2016 в 06:48

Это простая структура XML. Если вам нужно «сгладить» его в таблицу SQL, вы можете сделать это с помощью синтаксиса XPATH, как показано ниже.

declare @xml xml = '
<responses>
  <response>
    <id>UniqueRowID</id>
    <value>16</value>
  </response>
  <response>
    <id>Language</id>
    <value>en-GB</value>
  </response>
  <response>
    <id>UserId</id>
    <value>21</value>
  </response>
</responses>
';
select
  T.c.value('(id)[1]','nvarchar(100)') as UniqueRowID
 ,T.c.value('(value)[1]','nvarchar(100)') as Language
from
  @xml.nodes('/responses/response') T(c)

Это даст вам такие данные:

UniqueRowID | Language
======================
UniqueRowID | 16
Language    | en-GB
UserId      | 21

Я немного не понимаю, что вы имеете в виду, когда пишете:

В следующем столбце могут быть другие данные. id & amp; ценность общая для всех. Но некоторые идентификаторы в одном ряду могут не находиться в другом.

Также кажется, что вы структурировали эти данные способом, который не очень хорошо подходит для XML. В идеале каждый элемент ответа должен иметь одинаковые компоненты.

Вы можете подумать о чем-то более похожем (просто пища для размышлений):

<responses>
  <response>
    <UniqueRowID>100</UniqueRowID>
    <UserId>16</id>
    <Language>EN-GB</value>
  </response>
  <response>
    <UniqueRowID>200</UniqueRowID>
    <UserId>17</id>
    <Language>ES</value>
  </response>
  <response>
    <UniqueRowID>300</UniqueRowID>
    <UserId>18</id>
    <Language>DE</value>
  </response>
</responses>
2
JosephStyons 2 Май 2016 в 17:48