问题
Suppose I store employee data in a xml
column in my log table. Sometimes data is also updated in the xml
column from a stored procedure.
Here is the sample example
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>'
There is some difference in two the xml
data which I need to show like old value & new value as a output of sql
Old Value New Value
--------- ---------
1005 1006
12/02/1981 05/02/1981
ACC001 ACC002
10,500 10,900
I just need to show the difference like above. So please guide me how to compare two xml data using XQuery and show the difference only in the above fashion in SQL Server. Please guide me with code snippet. thanks
回答1:
;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, '')
Result:
NodeName Value1 Value2
-------------------- -------------------- --------------------
EmpID 1005 1006
DOB 12/02/1981 05/02/1981
DeptID ACC001 ACC002
Salary 10,500 10,900
回答2:
I don't have the exact output you wanted - but at least you get a good comparison of old and new values:
;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
Gives you an output of:
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 is great for storing and manipulating data - but presentation like this should be done in a front-end application (like an ASP.NET application) - not in T-SQL....
回答3:
I am too late here !!! However I found that if employees XML as shown above has multiple records then the JOIN query with CTE returns incorrect results.
I have below XML input
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>'
I will use below query to find the difference
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)
Hope this helps !!!
来源:https://stackoverflow.com/questions/8762725/compare-two-sets-of-xml-data-using-xquery-in-sql-server