2012-01-06 7 views
8

Supponiamo di archiviare i dati dei dipendenti in una colonna xml nella tabella dei registri. A volte i dati vengono aggiornati anche nella colonna xml da una stored procedure.Confrontare due insiemi di dati XML utilizzando XQuery in SQL Server

Ecco l'esempio del campione

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>' 

V'è una certa differenza di due dati xml che ho bisogno di mostrare come il vecchio valore & nuovo valore come uscita di SQL

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

ho appena bisogno di mostrare la differenza come sopra. Quindi, per favore mi guida come confrontare due dati xml utilizzando XQuery e mostrare la differenza solo nella modalità sopra in SQL Server. Per favore guidami con lo snippet di codice. grazie

risposta

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, '')  

Risultato:

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

è stato fantastico .... grazie – Thomas

+1

+1 eccellente lavoro - ho continuato a studiare come ottenere ciò e non ho visto la foresta per gli alberi! –

+0

cosa cambiare nel tuo codice per mostrare i dati che mostrano i dati di marc_s, ma non voglio codificare il nome del campo come marc_s. puoi aiutarmi. grazie – Thomas

2

Non ho l'uscita esatto si voleva - ma almeno si ottiene un buon confronto di valori vecchi e nuovi:

;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 

fornisce una potenza di:

  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 è ottimo per memorizzando e manipolando i dati, ma la presentazione come questa dovrebbe essere eseguita in un'applicazione front-end (come un'applicazione ASP.NET) - non in T-SQL ....

+0

Il tuo sforzo è stato buono, ma sei difficile codificare il nome del campo che non voglio. grazie – Thomas

0

Sono troppo tardi qui !!! Tuttavia ho scoperto che se l'XML degli impiegati come mostrato sopra ha più record, allora la query JOIN con CTE restituisce risultati errati.

devo sotto input 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>' 

Userò qui sotto query per trovare la differenza

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) 

Spero che questo aiuti !!!