Select 并匹配来自两个 XML 列的值

Select and match values from two XML columns

我有两个XML。一个用于旧值,另一个用于新值。 XMl 都是 table.

的列

Table一个

| ID  | Old Value                        | New Value                        |
+-----+----------------------------------+----------------------------------+
| 1   | <Root>                           | <Root>                           |
|     | <ScreenrightsManagement>         | <ScreenrightsManagement>         |
|     | <SCREENRIGHTID>8</SCREENRIGHTID> | <SCREENRIGHTID>8</SCREENRIGHTID> |
|     | <SCREENID>9</SCREENID>           | <SCREENID>10</SCREENID>          |
|     | <ROLEID>1</ROLEID>               | <ROLEID>2</ROLEID>               |
|     | </ScreenrightsManagement>        | </ScreenrightsManagement>        |
|     | </Root>                          | </Root>                          |

预期输出:

  Table Name                Field Name       Old Value    New Value
  ScreenrightsManagement    SCREENRIGHTID    8            8
  ScreenrightsManagement    SCREENID         9            10
  ScreenrightsManagement    ROLEID           1            2

我需要 select 来自 XML 的值并获得预期的输出,如图所示。我该怎么做?

以下将从 XML 中提取所有名称和值并将它们连接在一起:

SELECT
    t.ID,
    o.nodes.value('local-name(.)', 'VARCHAR(100)') AS nodeName,
    o.nodes.value('.', 'VARCHAR(100)') value1,
    n.nodes.value('.', 'VARCHAR(100)') value2
FROM @tablea AS t
CROSS APPLY t.OldValue.nodes('/Root/ScreenrightsManagement/*') AS o(nodes)
CROSS APPLY t.NewValue.nodes('/Root/ScreenrightsManagement/*') AS n(nodes)
WHERE o.nodes.value('local-name(.)', 'VARCHAR(100)') = n.nodes.value('local-name(.)', 'VARCHAR(100)')

Demo on DB Fiddle

以下查询将帮助您获得结果。

SELECT 
oldvalue.ID
,oldvalue.tablename
,oldvalue.Colname as fieldname
,oldvalue.ColValue as oldvalue
,newvalue.ColValue as newvalue

 FROM
(
SELECT 
    q.ID,
    t.p.value('local-name(.)', 'varchar(50)') as Colname,
    t.p.value('(.)[1]', 'varchar(50)') as ColValue,
    t.p.value('local-name(..)[1]', 'varchar(50)') as tablename
FROM #test q
    CROSS APPLY oldvalue.nodes('/Root/ScreenrightsManagement/*') t(p)
)oldvalue
inner join 
(
SELECT 
    q.ID,
    t.p.value('local-name(.)', 'varchar(50)') as Colname,
    t.p.value('(.)[1]', 'varchar(50)') as ColValue,
    t.p.value('local-name(..)[1]', 'varchar(50)') as tablename
FROM #test q
    CROSS APPLY newvalue.nodes('/Root/ScreenrightsManagement/*') t(p)
)newvalue ON newvalue.Id=oldvalue.Id and newvalue.Colname=oldvalue.Colname
 and newvalue.tablename=oldvalue.tablename