2012-01-06 58 views
8

假设我将员工数据存储在日志表的xml列中。有时,数据也会在存储过程的xml列中更新。在SQL Server中使用XQuery比较两组XML数据

这里是样品例如

DECLARE @XML1 XML 
DECLARE @XML2 XML 

SET @XML1 = 
'<NewDataSet> 
<Employee> 
<EmpID>1005</EmpID> 
<Name> keith </Name> 
<DOB>12/02/1981</DOB> 
<DeptID>ACC001</DeptID> 
<Salary>10,500</Salary> 
</Employee> 
</NewDataSet>' 

SET @XML2 = 
'<NewDataSet> 
<Employee> 
<EmpID>1006</EmpID> 
<Name> keith </Name> 
<DOB>05/02/1981</DOB> 
<DeptID>ACC002</DeptID> 
<Salary>10,900</Salary> 
</Employee> 
</NewDataSet>' 

中有两个xml数据,我需要表现出像旧值&新值作为SQL的输出

Old Value    New Value 
---------    --------- 
1005     1006 
12/02/1981   05/02/1981 
ACC001    ACC002 
10,500    10,900 

我只是有些区别需要显示如上所述的差异。因此,请指导我如何使用XQuery比较两个xml数据,并仅在SQL Server中以上述方式显示差异。请用代码片段指导我。感谢

回答

15
;with XML1 as 
(
    select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName, 
     T.N.value('.', 'nvarchar(100)') as Value 
    from @XML1.nodes('/NewDataSet/Employee/*') as T(N) 
), 
XML2 as 
(
    select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName, 
     T.N.value('.', 'nvarchar(100)') as Value 
    from @XML2.nodes('/NewDataSet/Employee/*') as T(N) 
) 
select coalesce(XML1.NodeName, XML2.NodeName) as NodeName, 
     XML1.Value as Value1, 
     XML2.Value as Value2 
from XML1 
    full outer join XML2 
    on XML1.NodeName = XML2.NodeName 
where coalesce(XML1.Value, '') <> coalesce(XML2.Value, '')  

结果:

NodeName    Value1    Value2 
-------------------- -------------------- -------------------- 
EmpID    1005     1006 
DOB     12/02/1981   05/02/1981 
DeptID    ACC001    ACC002 
Salary    10,500    10,900 
+0

这真是棒极了....谢谢 – Thomas 2012-01-07 16:45:49

+1

+1优秀的工作 - 我一直在研究如何实现这一点,只是没有看到树木的森林! – 2012-01-07 16:55:23

+0

什么改变在我们的代码来显示数据如何marc_s数据显示,但我不想像marc_s硬编码字段名称。你能帮助吗?谢谢 – Thomas 2012-01-09 06:32:02

2

我没有你想要的确切输出 - 但至少你得到新旧值的一个很好的比较:

;WITH OldData AS 
(
SELECT 
    @XML1.value('(/NewDataSet/Employee/EmpID)[1]', 'int') AS 'EmpID', 
    @XML1.value('(/NewDataSet/Employee/Name)[1]', 'varchar(50)') AS 'Name', 
    @XML1.value('(/NewDataSet/Employee/DOB)[1]', 'datetime') AS 'DOB', 
    @XML1.value('(/NewDataSet/Employee/DeptID)[1]', 'varchar(50)') AS 'DeptID', 
    @XML1.value('(/NewDataSet/Employee/Salary)[1]', 'varchar(25)') AS 'Salary' 
), 
NewData AS 
(
SELECT 
    @XML2.value('(/NewDataSet/Employee/EmpID)[1]', 'int') AS 'EmpID', 
    @XML2.value('(/NewDataSet/Employee/Name)[1]', 'varchar(50)') AS 'Name', 
    @XML2.value('(/NewDataSet/Employee/DOB)[1]', 'datetime') AS 'DOB', 
    @XML2.value('(/NewDataSet/Employee/DeptID)[1]', 'varchar(50)') AS 'DeptID', 
    @XML2.value('(/NewDataSet/Employee/Salary)[1]', 'varchar(25)') AS 'Salary' 
) 
SELECT 
    'Old values', od.* 
FROM OldData od 
UNION 
SELECT 'New values', nd.* 
FROM NewData nd 

给你的输出:

  EmpID Name DOB      DeptID Salary 
Old values 1005 keith 1981-12-02 00:00:00.000 ACC001 10,500 
New values 1006 keith 1981-05-02 00:00:00.000 ACC002 10,900 

SQL Server非常适合存储和操纵数据 - 但这样的演示应该在前端应用程序(如ASP.NET应用程序)中完成 - 而不是在T-SQL中执行....

+0

你的努力是好的,但你很难编码我不想要的字段名称。谢谢 – Thomas 2012-01-07 16:46:26

0

我太晚了这里!但是我发现如果上面显示的雇员XML有多个记录,那么使用CTE的JOIN查询会返回不正确的结果。

我有以下XML输入

DECLARE @XML1 XML 
DECLARE @XML2 XML 

SET @XML1 = 
'<NewDataSet> 
<Employees> 
    <Employee> 
     <Name> keith </Name> 
     <EmpID> 1005 </EmpID> 
     <DOB>12/02/1981</DOB> 
     <DeptID>ACC001</DeptID> 
     <Salary>10,500</Salary> 
    </Employee> 
    <Employee> 
     <Name> keith </Name> 
     <EmpID> 1004 </EmpID> 
     <DOB>12/02/1981</DOB> 
     <DeptID>ACC001</DeptID> 
     <Salary>10,500</Salary> 
    </Employee> 
</Employees> 
</NewDataSet>' 

    SET @XML2 = 
    '<NewDataSet> 
    <Employees> 
     <Employee> 
      <Name> keith </Name> 
      <EmpID> 1005 </EmpID> 
      <DOB>12/02/1981</DOB> 
      <DeptID>ACC001</DeptID> 
      <Salary>10,500</Salary> 
     </Employee> 
     <Employee> 
      <Name> keith </Name> 
      <EmpID> 1004 </EmpID> 
      <DOB>12/02/1981</DOB> 
      <DeptID>ACC001</DeptID> 
      <Salary>10,501</Salary> 
     </Employee> 
     <Employee> 
      <Name> keith1 </Name> 
      <EmpID> 10040 </EmpID> 
      <DOB>12/02/1981</DOB> 
      <DeptID>ACC001</DeptID> 
      <Salary>10,501</Salary> 
     </Employee> 
    </Employees> 
    </NewDataSet>' 

我会用下面的查询,找到差异

select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName, 
T.N.value('.', 'nvarchar(100)') as Value 
from @XML2.nodes('/NewDataSet/Employees/Employee/*') as T(N) 

EXCEPT 

select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName, 
T.N.value('.', 'nvarchar(100)') as Value 
from @XML1.nodes('/NewDataSet/Employees/Employee/*') as T(N) 

希望这有助于!