我有一些表示数学表达式树的XML数据,并希望将其转换为平面数学公式。听起来很简单,但SQL Server中的XQuery限制目前阻止了我的成功(没有递归函数,“异构”结果的问题等)。
表达式可以是任意嵌套深度。这是一个示例(数据稍后会在表的xml列中,但这对于此处的测试来说已经足够了):
DECLARE @expr xml;
SET @expr = '<expression aggregator="+">
<indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
<indicator>7DD46849-2193-EB41-8BAB-CE0C45255249</indicator>
<expression aggregator="*">
<expression aggregator="/">
<indicator>122F277B-A241-7944-BC38-3BB5E8B213AF</indicator>
<indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
</expression>
<indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
<value>12</value>
</expression>
<expression aggregator="-">
<indicator>ADFCEF34-9877-DE4E-8A00-13576437D82B</indicator>
<indicator>75896474-C197-1C44-8EAA-8FE9D0AB2663</indicator>
</expression>
<indicator>27F3156D-FDA7-1E44-B545-7F27A48D9838</indicator>
</expression>';
所需的结果是(空白无关紧要):
(
[122F277B-A241-7944-BC38-3BB5E8B213AF] +
[7DD46849-2193-EB41-8BAB-CE0C45255249] +
(
(
[122F277B-A241-7944-BC38-3BB5E8B213AF] /
[27F3156D-FDA7-1E44-B545-7F27A48D9838]
) *
[ADFCEF34-9877-DE4E-8A00-13576437D82B] *
12
) +
(
[ADFCEF34-9877-DE4E-8A00-13576437D82B] -
[75896474-C197-1C44-8EAA-8FE9D0AB2663]
) +
[27F3156D-FDA7-1E44-B545-7F27A48D9838]
)
有人在SQL Server 2008(R2)中掌握XQuery是否足以执行此转换?
答案 0 :(得分:1)
不漂亮,但似乎有效。递归UDF。
create function GetExpression(@expr xml) returns varchar(max)
as
begin
declare @max int
declare @i int = 1
declare @nodetype varchar(50)
declare @aggregator char(1)
declare @res varchar(max) = '('
declare @value varchar(36)
declare @SubExpr xml
select @max=count(*)
from @expr.nodes('/expression/*') as n(e)
select @aggregator = n.e.value('@aggregator', 'char(1)')
from @expr.nodes('expression') as n(e)
while @i <= @max
begin
select
@nodetype = x.value('local-name(.)[1]', 'varchar(36)'),
@value = x.value('.', 'varchar(36)'),
@SubExpr = x.query('.')
from @expr.nodes('/expression/*[position()=sql:variable("@i")]') e(x)
if @nodetype = 'indicator'
set @res = @res + '[' + @value + ']'
else
if @nodetype = 'expression'
set @res = @res + dbo.GetExpression(@SubExpr)
else
if @nodetype = 'value'
set @res = @res + @value
if @i < @max
set @res = @res + @aggregator
set @i = @i + 1
end
set @res = @res + ')'
return @res
end
答案 1 :(得分:1)
Mikael,你让我走上正轨,这是我的最终解决方案:
CREATE FUNCTION dbo.GetExpression (@expr xml)
RETURNS varchar(max)
AS
BEGIN
RETURN STUFF(
( SELECT a.x.value('.', 'char'), CASE
WHEN v.x.exist('self::expression')=1 THEN '('+dbo.GetExpression(v.x.query('.'))+')'
WHEN v.x.exist('self::indicator')=1 THEN '['+REPLACE(v.x.value('.', 'varchar(35)'), '-', '')+']'
ELSE v.x.value('.', 'varchar(20)')
END
FROM @expr.nodes('expression/@aggregator') a(x)
CROSS APPLY @expr.nodes('expression/*') v(x)
FOR XML PATH('')
),
1, 1, '');
END