如何使这个SQL函数更快地解析XML

时间:2016-08-02 07:52:27

标签: sql-server xml umbraco sqlxml

我很难找到一种方法来改进这个自定义SQL脚本到Umbraco数据库。

这是用于获取和解析xml并选择正确值的sql脚本:

DECLARE @Title nvarchar(1000)
SET @Title =
(SELECT @NodeXml.query('//TechnicalData/title' ).value('.', 'nvarchar(max)') Title
FROM cmsContentXml xt JOIN umbracoNode un ON un.id = xt.NodeId
WHERE xt.nodeId = @NodeId)

SELECT iif(CHARINDEX('"values":null', @Title,0) > 0,'',Substring(@Title, 21, CHARINDEX('}', @Title) - 22)) Title

部分XML如下:

<?xml version="1.0"?>
<TechnicalData id="1261" key="b6a2f67a-0f0f-40dd-a3c6-c5fb9d8b78b9" parentID="1092" level="3" creatorID="0" sortOrder="12" createDate="2016-07-14T13:56:37" updateDate="2016-07-15T12:06:25" nodeName="Rioolkolken Type 1 Drainerend via de zijwanden" urlName="rioolkolken-type-1-drainerend-via-de-zijwanden" path="-1,1089,1092,1261" isDoc="" nodeType="1154" creatorName="admin" writerName="Karl" writerID="1" template="1085" nodeTypeAlias="TechnicalData">
    <title>{"values":{"nl-BE":"Rioolkolken Type 1 Drainerend via de zijwanden"},"dtdGuid":"f2dfa88e-63b9-4913-80cd-64d770cef90e"}</title>
</TechnicalData>

这只是脚本的一小部分。 TechnicalData包含大约20个节点,所有节点都必须进行解析。完整的脚本可以找到here

这个自定义脚本的原因是因为我需要使用ssrs报告扩展Umbraco站点。

2 个答案:

答案 0 :(得分:1)

解析单个选择中的所有节点

DECLARE @NodeXml xml;

-- sample data
SET @NodeXml ='<TechnicalData id="1261" key="b6a2f67a-0f0f-40dd-a3c6-c5fb9d8b78b9" parentID="1092" level="3" creatorID="0" sortOrder="12" createDate="2016-07-14T13:56:37" updateDate="2016-07-15T12:06:25" nodeName="Rioolkolken Type 1 Drainerend via de zijwanden" urlName="rioolkolken-type-1-drainerend-via-de-zijwanden" path="-1,1089,1092,1261" isDoc="" nodeType="1154" creatorName="admin" writerName="Karl" writerID="1" template="1085" nodeTypeAlias="TechnicalData">
    <title>{"values":{"nl-BE":"Rioolkolken Type 1 Drainerend via de zijwanden"},"dtdGuid":"f2dfa88e-63b9-4913-80cd-64d770cef90e"}</title>
</TechnicalData>';

DECLARE @Title nvarchar(1000);
DECLARE @Subtitle nvarchar(1000)
DECLARE @Company int;
DECLARE @Date Datetime;

SELECT @Date = @NodeXml.value('(/TechnicalData/@createDate)[1]', 'datetime')
 ,@Title = td.node.value('title[1]','nvarchar(max)')
 ,@Subtitle = td.node.value('subtitle[1]','nvarchar(max)')
 ,@Company = td.node.value('bedrijf[1]','int')
 -- and so on
FROM  @NodeXml.nodes('TechnicalData') td(node);

--check it
SELECT @Date,@Title,@Subtitle,@Company ;

答案 1 :(得分:1)

您的方法很慢,因为您一遍又一遍地从XML中获取一点信息。

通过这种方法,你可以在一个文件中获得所有数据类型安全,而不需要任何字符串解析。

DECLARE @NodeXml XML=
N'<?xml version="1.0"?>
<TechnicalData id="1261" key="b6a2f67a-0f0f-40dd-a3c6-c5fb9d8b78b9" parentID="1092" level="3" creatorID="0" sortOrder="12" createDate="2016-07-14T13:56:37" updateDate="2016-07-15T12:06:25" 
nodeName="Rioolkolken Type 1 Drainerend via de zijwanden" urlName="rioolkolken-type-1-drainerend-via-de-zijwanden" path="-1,1089,1092,1261" isDoc="" nodeType="1154" creatorName="admin" writerName="Karl" writerID="1" template="1085" nodeTypeAlias="TechnicalData">
    <title>{"values":{"nl-BE":"Rioolkolken Type 1 Drainerend via de zijwanden"},"dtdGuid":"f2dfa88e-63b9-4913-80cd-64d770cef90e"}</title>
</TechnicalData>';

SELECT td.value('@id','int') AS id
      ,td.value('@key','uniqueidentifier') AS [key]
      ,td.value('@parentID','int') AS parentID
      ,td.value('@level','int') AS [level]
      ,td.value('@creatorID','int') AS creatorID
      ,td.value('@sortOrder','int') AS sortOrder
      ,td.value('@createDate','datetime') AS createDate
      ,td.value('@updateDate','datetime') AS updateDate
      ,td.value('@nodeName','nvarchar(max)') AS nodeName
      ,td.value('@urlName','nvarchar(max)') AS urlName
      ,td.value('@path','nvarchar(max)') AS [path]
      ,td.value('@isDoc','nvarchar(max)') AS isDoc
      ,td.value('@nodeType','int') AS nodeType
      ,td.value('@creatorName','nvarchar(max)') AS creatorName
      ,td.value('@writerName','nvarchar(max)') AS writerName
      ,td.value('@writerID','int') AS writerID
      ,td.value('@template','int') AS template
      ,td.value('@nodeTypeAlias','nvarchar(max)') AS nodeTypeAlias

      ,td.value('title[1]','nvarchar(max)') AS Title

FROM @NodeXml.nodes('TechnicalData') AS A(td)

这种情况下的结果是一行,所有数据都在列中。

我怀疑,你需要在声明的变量中使用你的值,更好地使用上面的CTE(基于集合/内联/ ad-hoc 在大多数情况下优于程序)并使用那里的值。但是:很容易将收集的信息填充到声明的变量中(如果真的需要)。在这种情况下,只需使用正确的类型声明变量并使用语法

SELECT @MyVariable=td.value('@id','int') 
      ,@OtherVariable= ...
... same for the rest...