从不一致的xml C#/ SQL

时间:2018-04-27 12:20:31

标签: c# sql-server xml ssis

我在SQL Server 2016中有一个临时表,它有许多XML数据。我需要的是获取每个XML,从中读取数据以输入另一个表并从临时表中删除数据。 但是,我有两个问题。一个是XML的架构不一致。对于一些人来说,可能会有额外的节点,而对于其他节点,它不会在那里。此外,对于每个XML,我必须循环多个消息以为主表创建多个行。其次,我已经尝试过使用“CROSS APPLY' (我可能错过了一些连接,但数据无论如何都会出现)结果是每20秒收到1条消息,尝试SSIS(再次缺少1-2个连接,但数据无论如何都会出现),结果是每8秒收到1条消息。最后,我创建了C#控制台代码,以便在datatable中获取消息,将其转换为XML文档,检查节点是否存在,根据需要进行循环,最后再次将其插入数据库,每秒大约需要3-4条消息。 / p>

现在我的问题是,我想让它更快(理想情况下每分钟1000条消息)。任何人都可以提出更好的方法来实现这个目标吗?

编辑:( XML看起来如下所示)

<Step1>
  <MetaData>
    <Node1>Value</Node1>
    <Node2>Value</Node2>
  </MetaData>
  <ActualData>
    <MainNode>
      <Child1>
        <NodeA>Value</NodeA>
      </Child1>
      <Child2>
        <Numbers>
          <Child a="b">LoopValue</Child>
          <Optional a="b">AdditionalLoopValue</Optional>
        </Numbers>
        <Alphabets>
          <Child a="b">
            <Child1>
              <Sub1>Value</Sub1>
              <Sub2>Value</Sub2>
            </Child1>
            <Child2>
              <Sub1>Value</Sub1>
              <Sub2>Value</Sub2>
            </Child2>
          </Child>
          <Optional a="b">
            <Child1>
              <Sub1>Value</Sub1>
              <Sub2>Value</Sub2>
            </Child1>
            <Child2>
              <Sub1>Value</Sub1>
              <Sub2>Value</Sub2>
            </Child2>
          </Optional>
        </Alphabets>
      </Child2>
      <Child3>
        <Loop1>
          <Child1>Value</Child1>
          <Child2>
            <Sub1>Value</Sub1>
          </Child2>
          <Child3>
            <Sub1>Value</Sub1>
            <Sub2>Value</Sub2>
          </Child3>
          <Child4>Value</Child4>
        </Loop1>
        <Loop2>
          <Child1>Value</Child1>
          <Child2>
            <Sub1>Value</Sub1>
          </Child2>
          <Child3>
            <Sub1>Value</Sub1>
            <Sub2>Value</Sub2>
          </Child3>
          <Child4>Value</Child4>
          <Optional1>
            <Sub1>Value</Sub1>
            <Sub2>Value</Sub2>
          </Optional1>
        </Loop2>
      </Child3>
    </MainNode>
  </ActualData>
</Step1>

编辑2 :(代码如下所示)

string a,b,c;
DataTable dt;
foreach on DataTable.Rows
{    foreach node on nodelist
     {   if Node1.ChildNode !=null
            {a=Node1.ChildNode["NodeName"]}
        if Node1.ChildNode !=null
            {b=Node1.ChildNode["NodeName"]}
        for loop on b
            {if Node1.ChildNode != null
                {c=Node1.ChildNode["NodeName"]}
            dt.Rows.Add(a,b,c);}}
    delete from temp table based on id.
    add records from dt to main table
    dt.Rows.Clear();}

2 个答案:

答案 0 :(得分:0)

public string str { get; private set; }

private void RecursiveSearchInXmlWithString(XmlNode xmlnode, string nametofind)
    {
        // check if node has children, if so then it recursively search the children too
        if (xmlnode.HasChildNodes)
        {
            for (int i = 0; i < xmlnode.ChildNodes.Count; i++)
            {
                RecursiveSearchInXmlWithString(xmlnode.ChildNodes[i], nametofind);
            }
        }
        // here is the element that we are searching for 
        if (xmlnode.Name == nametofind)
        {
            str = xmlnode.InnerText;
        }
    }

我有一个resursive函数与这个类的公共全局变量。 str只捕获正确的值,调用后可以使用str。在每个节点之后,你必须捕获str。你可以在此之后搞清楚。

您还需要使用if语句处理所有可能的情况。

答案 1 :(得分:0)

如果这些XML很大并且你有很多这样的XML,那么将数据转移到你的C#应用​​程序并创建一个XML文档以便阅读它需要花费大量的时间。如果该列是本机XML列,那么在SQL-Server中完成此工作将会快得多。

您的XML是深层嵌套的。我希望,在任何情况下你都可以依赖某种结构。

只是暗示你可以如何继续:

SELECT @xml.value(N'(/Step1/MetaData/Node1/text())[1]',N'nvarchar(max)') AS Meta1
      ,@xml.value(N'(/Step1/MetaData/Node2/text())[1]',N'nvarchar(max)') AS Meta2
      ,childNode.value(N'local-name(.)','nvarchar(max)') AS ChildNode

      ,lvl2Numbers.value(N'(Child/@a)[1]',N'nvarchar(max)') AS NumberChildA
      ,lvl2Numbers.value(N'(Child/text())[1]',N'nvarchar(max)') AS NumberChildText
      ,lvl2Numbers.value(N'(Optional/@a)[1]',N'nvarchar(max)') AS NumberOptionalA
      ,lvl2Numbers.value(N'(Optional/text())[1]',N'nvarchar(max)') AS NumberOptionalText

      ,lvl2Alpha.query(N'.') AS lvl2Alpha
      --add further levels here

      ,lvl2Loop.query(N'.') AS lvl2Loop
      --add further levels here
FROM @xml.nodes(N'/Step1/ActualData/MainNode/*') AS A(childNode)

OUTER APPLY childNode.nodes(N'*[local-name()="Numbers"]') AS B1(lvl2Numbers)

OUTER APPLY childNode.nodes(N'*[local-name()="Alphabets"]') AS B2(lvl2Alpha)
OUTER APPLY lvl2Alpha.nodes(N'Child') AS B2a(ChildrenOfAlpha)
OUTER APPLY ChildrenOfAlpha.nodes(N'*') AS B2aa(SubChildrenOfAlpha)
OUTER APPLY SubChildrenOfAlpha.nodes(N'*') AS B2ab(SubsInSubChildrenOfAlpha)
OUTER APPLY lvl2Alpha.nodes(N'Optional') AS B2b(OptionalOfAlpha)
OUTER APPLY OptionalOfAlpha.nodes(N'*') AS B2ba(SubOptionalOfAlpha)
OUTER APPLY SubOptionalOfAlpha.nodes(N'*') AS B2bb(SubsInSubOptionalOfAlpha)

OUTER APPLY childNode.nodes(N'*[substring(local-name(),1,4)="Loop"]') AS B3(lvl2Loop)
--and so on

通过这样的查询,您可以逐步降低层次结构,并在非规范化的宽表中返回整个所有。但这不会很快......

我为每种数据结构创建一个查询,并使用T-SQL作为逻辑,或使用.query()调用并将此结果加载到C#中以处理那里的小片段。

提示

如果此XML的构造在您的控制之下,请尝试避免使用名称编号的元素(<Child1>, <Child2> ...)如果需要,请将其更改为<Child nr="1">, <Child nr="2"> ... - 更好并且更快阅读...