【问题标题】:How can I make this SQL function that parses XML faster如何使这个解析 XML 的 SQL 函数更快
【发布时间】:2016-08-02 07:52:27
【问题描述】:

我很难找到一种方法来将此自定义 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 站点。

【问题讨论】:

  • 您使用什么版本的 SQL Server? title 的内容是 SQL Server 2016 中的 JSON,您可以使用 parseJSON
  • 我知道,但它是 2012 年安装的。为其他偶然发现此问题的人 +1

标签: sql-server xml umbraco sqlxml


【解决方案1】:

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

有了这个,您可以一次性从 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(基于集合/内联/临时在大多数情况下比 程序化 strong>) 并使用那里的值。但是:也很容易将收集到的信息填充到声明的变量中(如果确实需要)。在这种情况下,只需使用正确的类型声明变量并使用语法

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

【讨论】:

  • 这确实加快了速度。我还最终将查询放在存储过程中,以绕过为每个声明创建查询参数的需要,因为 ssrs 似乎自动将查询顶部的每个声明的 var 绑定为查询参数...
【解决方案2】:

在一次选择中解析所有节点

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 ;

【讨论】:

  • 您的回答是正确的,但 Snugo 的回答更为详尽。 +1 虽然
猜你喜欢
  • 1970-01-01
  • 2017-05-20
  • 2013-06-09
  • 2020-11-28
  • 1970-01-01
  • 2012-02-27
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多