2012-01-06 72 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) 

希望這有助於!