【问题标题】:Compare two sets of XML data using XQuery in SQL Server在 SQL Server 中使用 XQuery 比较两组 XML 数据
【发布时间】:2012-01-06 18:37:13
【问题描述】:

假设我将员工数据存储在日志表的xml 列中。有时还会从存储过程中更新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 中仅以上述方式显示差异。请用代码 sn-p 指导我。谢谢

【问题讨论】:

    标签: sql-server-2005 tsql xquery-sql


    【解决方案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, '')    
    

    结果:

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

    【讨论】:

    • +1 出色的工作 - 我一直在研究如何实现这一目标,只是没有只见树木不见森林!
    • 在你的代码中改变什么以显示数据是如何显示 marc_s 数据的,但我不想硬编码像 marc_s 这样的字段名称。你能帮忙吗?谢谢
    • 您需要使用 pivot 并且当您想要可变数量的列时,您需要动态地执行它。看看这里的动态枢轴。 simple-talk.com/community/blogs/andras/archive/2007/09/14/… 将此查询的结果存储在表变量中,然后对表变量执行文章中的动态数据透视。
    • @Mikael “T.N.”在哪里东西来自哪里?
    • @Question_Guy 节点函数将 XML 分解为表。 T 是表别名,N 是列名。 ` from @XML1.nodes('/NewDataSet/Employee/*') as T(N)` 不一定非要T(N),你自己决定要使用什么别名和列名。
    【解决方案2】:

    我没有你想要的 exact 输出 - 但至少你可以很好地比较新旧值:

    ;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... .

    【讨论】:

    • 你的努力很好,但你硬编码了我不想要的字段名称。谢谢
    【解决方案3】:

    我来晚了!!!但是我发现如果上面显示的员工 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)
    

    希望对你有帮助!!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 2020-12-03
      • 1970-01-01
      • 2011-08-31
      相关资源
      最近更新 更多