高效碎片以元素为中心的XML TSQL

时间:2014-04-03 16:24:48

标签: sql-server xml performance tsql xquery-sql

我试图粉碎具有多层嵌套元素的XML文档:

<server>
            <name>111.111.11.11</name>
            <displayName>EVIL SERVER</displayName>
            <comment />
            <logonCredentials inherit="None">
                <userName>user</userName>
                <domain>DOMAIN</domain>
                <password storeAsClearText="True">xxxxxxx</password>
            </logonCredentials>
            <connectionSettings inherit="FromParent" />
            <gatewaySettings inherit="FromParent" />
            <remoteDesktop inherit="FromParent" />
            <localResources inherit="None">
                <audioRedirection>2</audioRedirection>
                <audioRedirectionQuality>2</audioRedirectionQuality>
                <audioCaptureRedirection>0</audioCaptureRedirection>
                <keyboardHook>2</keyboardHook>
                <redirectClipboard>True</redirectClipboard>
                <redirectDrives>True</redirectDrives>
                <redirectPorts>False</redirectPorts>
                <redirectPrinters>False</redirectPrinters>
                <redirectSmartCards>False</redirectSmartCards>
            </localResources>
            <securitySettings inherit="FromParent" />
            <displaySettings inherit="FromParent" />
        </server>
        <server>
            <name>111.12.11.11</name>
            <displayName>NICE SERVER</displayName>
            <comment />
            <logonCredentials inherit="None">
                <userName>user2</userName>
                <domain>DOMAIN2</domain>
                <password storeAsClearText="True">xxxxxxx</password>
            </logonCredentials>
            <connectionSettings inherit="FromParent" />
            <gatewaySettings inherit="FromParent" />
            <remoteDesktop inherit="FromParent" />
            <localResources inherit="FromParent" />
            <securitySettings inherit="FromParent" />
            <displaySettings inherit="FromParent" />
        </server>

我希望将它们返回到一个表中,其中包含从服务器名称到登录凭据的所有值。

我已经能够使用CROSS APPLY这样做:(不完整)

 SELECT
    name = n.value('name[1]','varchar(15)'),
    displayName = dn.value('.','varchar(8000)'),
    comment = c.value('.','varchar(8000)'),
    userName = un.value('.','varchar(8000)'),
    domain = d.value('.','varchar(8000)'),
    [password] = p.value('.','varchar(8000)'),
    connectionSettings = cs.value('.','varchar(8000)')
    audioRedirection = ar.value('.', 'varchar(8000)')
FROM @RDCM.nodes('/group/server') AS s(n)
    CROSS APPLY s.n.nodes('displayName') s1(dn)
    CROSS APPLY s.n.nodes('comment') s2(c)
    CROSS APPLY s.n.nodes('logonCredentials') s4(lc)
        CROSS APPLY s4.lc.nodes('userName') lc1(un)
        CROSS APPLY s4.lc.nodes('domain') lc2(d)
        CROSS APPLY s4.lc.nodes('password') lc3(p)
    CROSS APPLY s.n.nodes('connectionSettings') s3(cs)
    CROSS APPLY s.n.nodes('localResources') s8(lr)
        OUTER APPLY s8.lr.nodes('audioRedirection') lr1(ar)

但是,我只是开始构建这个查询,并且很清楚它将永远运行。

我也尝试过OPENXML,但我只能获得一个级别。

2 个答案:

答案 0 :(得分:0)

我不会在Transact-SQL中这样做。虽然您可以在SQL Server中处理XML,但如果您无法在更高级别处理更好(更快)的工具,那么您只想在那里执行XML。

如果是这样的话,我会在C#中编写一组简单的类,它们是XElement的子类,并公开一个名为StuffParameters()的方法以方便你的插入/更新语句。因为XML碎化是如此之多,在.Net中更容易做....

// Typed in the editor -- code needs to be eval'd before attempting to compile!
public class ServerData: XElement
{
    public ServerData(string strServer): base(strServer)
    {
        // Base class initializes XElement with XML, throws error if XML not well-formed
    }

    // Properties
    public string Name    // One example of the two dozen properties you'll need
    {
        get()
        {
            return GetAttribute("name");
        }
    }

    // StuffParameters
    public bool StuffParameters(SqlCommand objCommand)
    {
        // In real life you'd use try...catch, but this is prototype code, right?
        objCommand.Parameters["@ServerName"].Value = Name;
        // ... and so forth
    }
}

从您的服务器XDocuments列表开始;为每个创建此类的实例。创建与数据库的连接,并使用存储过程创建SqlCommand对象。迭代这些类的列表,将命令传递给每个类实例的StuffParameters()方法。

当函数返回时,在命令上调用ExecuteNonQuery(),并将记录插入到表中。

更少的编码,以及更正统的处理XML的方式 - 所以如果你不得不改变它,你最终不会有一个需要花费数小时思考的头脑清理方法。

希望这可以帮助你......

答案 1 :(得分:0)

这实际上比你期望的要简单得多。您可以使用单个.nodes()函数轻松遍历XML,然后在.value()函数中指定子路径:

SELECT n.value('(./name/text())[1]','varchar(15)') AS [name],
       n.value('(./displayName/text())[1]','varchar(15)') AS [displayName],
       n.value('(./comment/text())[1]','varchar(15)') AS [comment],
  n.value('(./logonCredentials/userName/text())[1]','varchar(15)') AS [userName],
      n.value('(./logonCredentials/domain/text())[1]','varchar(15)') AS [domain],
  n.value('(./logonCredentials/password/text())[1]','varchar(15)') AS [password],
       n.value('(./connectionSettings/text())[1]','varchar(15)')
              AS [connectionSettings],
     n.value('(./gatewaySettings/text())[1]','varchar(15)') AS [gatewaySettings],
       n.value('(./remoteDesktop/text())[1]','varchar(15)') AS [remoteDesktop],
       n.value('(./localResources/audioRedirection/text())[1]','varchar(15)')
              AS [audioRedirection],
    n.value('(./localResources/audioRedirectionQuality/text())[1]','varchar(15)')
              AS [audioRedirectionQuality],
    n.value('(./localResources/audioCaptureRedirection/text())[1]','varchar(15)')
              AS [audioCaptureRedirection],
   n.value('(./securitySettings/text())[1]','varchar(15)') AS [securitySettings],
      n.value('(./displaySettings/text())[1]','varchar(15)') AS [displaySettings]
FROM @RDCM.nodes('/group/server') AS s(n)

完整测试:

DECLARE @RDCM XML
SET @RDCM = N'<group>
<server>
            <name>111.111.11.11</name>
            <displayName>EVIL SERVER</displayName>
            <comment />
            <logonCredentials inherit="None">
                <userName>user</userName>
                <domain>DOMAIN</domain>
                <password storeAsClearText="True">xxxxxxx</password>
            </logonCredentials>
            <connectionSettings inherit="FromParent" />
            <gatewaySettings inherit="FromParent" />
            <remoteDesktop inherit="FromParent" />
            <localResources inherit="None">
                <audioRedirection>2</audioRedirection>
                <audioRedirectionQuality>2</audioRedirectionQuality>
                <audioCaptureRedirection>0</audioCaptureRedirection>
                <keyboardHook>2</keyboardHook>
                <redirectClipboard>True</redirectClipboard>
                <redirectDrives>True</redirectDrives>
                <redirectPorts>False</redirectPorts>
                <redirectPrinters>False</redirectPrinters>
                <redirectSmartCards>False</redirectSmartCards>
            </localResources>
            <securitySettings inherit="FromParent" />
            <displaySettings inherit="FromParent" />
        </server>
        <server>
            <name>111.12.11.11</name>
            <displayName>NICE SERVER</displayName>
            <comment />
            <logonCredentials inherit="None">
                <userName>user2</userName>
                <domain>DOMAIN2</domain>
                <password storeAsClearText="True">xxxxxxx</password>
            </logonCredentials>
            <connectionSettings inherit="FromParent" />
            <gatewaySettings inherit="FromParent" />
            <remoteDesktop inherit="FromParent" />
            <localResources inherit="FromParent" />
            <securitySettings inherit="FromParent" />
            <displaySettings inherit="FromParent" />
        </server>
        </group>'


SELECT n.value('(./name/text())[1]','varchar(15)') AS [name],
       n.value('(./displayName/text())[1]','varchar(15)') AS [displayName],
       n.value('(./comment/text())[1]','varchar(15)') AS [comment],
n.value('(./logonCredentials/userName/text())[1]','varchar(15)') AS [userName],
    n.value('(./logonCredentials/domain/text())[1]','varchar(15)') AS [domain],
n.value('(./logonCredentials/password/text())[1]','varchar(15)') AS [password],
       n.value('(./connectionSettings/text())[1]','varchar(15)')
              AS [connectionSettings],
   n.value('(./gatewaySettings/text())[1]','varchar(15)') AS [gatewaySettings],
       n.value('(./remoteDesktop/text())[1]','varchar(15)') AS [remoteDesktop],
       n.value('(./localResources/audioRedirection/text())[1]','varchar(15)')
              AS [audioRedirection],
  n.value('(./localResources/audioRedirectionQuality/text())[1]','varchar(15)')
              AS [audioRedirectionQuality],
  n.value('(./localResources/audioCaptureRedirection/text())[1]','varchar(15)')
              AS [audioCaptureRedirection],
 n.value('(./securitySettings/text())[1]','varchar(15)') AS [securitySettings],
    n.value('(./displaySettings/text())[1]','varchar(15)') AS [displaySettings]
FROM @RDCM.nodes('/group/server') AS s(n)