如何创建一个 SQL 函数来解析多个 xml 格式的字符串?

问题描述

我正在尝试从 sql 中的价格列解析价格。我已经创建了一个函数来解析价格,但它只有在所有项目上的“所有”价格字符串都相同时才有效。我现在意识到我需要一个更强大的函数来解析多个价格配置。

这是我的简单 sql 查询

I.[NAME] AS 'ITEM NAME',DBO.parsePrice(I.PRICING) AS 'ITEM PRICE'
FROM ITEM I
order by 'ITEM NAME'

这是我的函数 DBO.parsePrice

RETURNS decimal(8,2) AS 
BEGIN
    RETURN CAST(@in AS XML).value(N'(/prices[@type="Level"]/item[@level="A"])[1]/@price',N'DECIMAL(14,2)');
END

这是只有一个价格级别的 XML 字符串。

<prices type="Level"><item level="A" price="10.00" /></prices>

函数将从上面的字符串中输出 10.00。

这是另一个示例,最多有 6 个不同的价格水平

<prices type="Level"><item level="A" price="10.00" /><item level="B" price="11.00" /><item level="C" price="12.00" /><item level="D" price="13.00" /><item level="E" price="14.00" /><item level="F" price="15.00" /></prices>

我的函数仅设计用于解析价格水平 (A)。为了让事情变得更加复杂,价格字符串也可以配置为不同的订单类型而不是价格水平。

<prices type="OrderType"><item level="DineIn" price="7" /><item level="TakeOut" price="8.00" /><item level="Delivery" price="" /><item level="Sale" price="" /></prices>

函数需要处理所有这些不同的情况。理想情况下,我希望每个价格区间都有单独的列,而不是一个以逗号分隔的字段。

任何帮助将不胜感激

问候,

JC

上述 sql 查询只是发布问题的一个示例。我的实际查询是使用左连接从其他表中提取数据。

SELECT
I.[NAME] AS 'ITEM NAME',DBO.parsePrice(I.PRICING) AS 'ITEM PRICE',ML.NAME AS 'MODIFIER LIST NAME',MG.NAME AS 'MODIFIER GROUP NAME',M.NAME AS 'MODIFIER NAME',M.UPCHARGE_EXPRESSION AS UPCHARGE
FROM ITEM I
LEFT JOIN [dbo].[ITEM_MODIFIER] IM ON IM.ITEM_RECORD_KEY = I.RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_LIST] ML ON ML.RECORD_KEY = IM.MODIFIER_LIST_RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_GROUP] MG ON MG.MODIFIER_LIST_RECORD_KEY = ML.RECORD_KEY
LEFT JOIN [dbo].[MODIFIER] M ON M.MODIFIER_GROUP_RECORD_KEY = MG.RECORD_KEY
order by 'ITEM NAME'

解决方法

您可以创建一个 TVF 返回(级别、价格)

spring.cloud.kubernetes.config.enabled=false

并在查询中使用它

create function DBO.parsePrice(@x xml)
returns table
return
select p.n.value('@level','nvarchar(100)') level,p.n.value('@price','decimal(9,2)') price
from @x.nodes('prices/item') p(n)

编辑

在 OP 说明之后,这是 TVF 的一个版本,它为非数字的 @price 返回 0

SELECT
I.[NAME] AS 'ITEM NAME',p.*,ML.NAME AS 'MODIFIER LIST NAME',MG.NAME AS 'MODIFIER GROUP NAME',M.NAME AS 'MODIFIER NAME',M.UPCHARGE_EXPRESSION AS UPCHARGE
FROM ITEM I
LEFT JOIN [dbo].[ITEM_MODIFIER] IM ON IM.ITEM_RECORD_KEY = I.RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_LIST] ML ON ML.RECORD_KEY = IM.MODIFIER_LIST_RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_GROUP] MG ON MG.MODIFIER_LIST_RECORD_KEY = ML.RECORD_KEY
LEFT JOIN [dbo].[MODIFIER] M ON M.MODIFIER_GROUP_RECORD_KEY = MG.RECORD_KEY
CROSS APPLY DBO.parsePrice(I.PRICING) p
order by 'ITEM NAME',p.Level
,

我已将 Serg 解决方案标记为正确的解决方案,即使我必须进行一些更改才能产生我们正在寻找的结果,而不会出现数据类型转换错误。这是我正在使用的完整解决方案。

SQL 查询

SELECT
I.[NAME] AS 'ITEM NAME',ic.NAME AS 'ITEM CATEGORY',M.UPCHARGE_EXPRESSION AS UPCHARGE
FROM ITEM I
LEFT JOIN [dbo].[ITEM_MODIFIER] IM ON IM.ITEM_RECORD_KEY = I.RECORD_KEY
LEFT JOIN [DBO].[ITEM_CATEGORY] IC ON IC.RECORD_KEY = I.ITEM_CATEGORY_RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_LIST] ML ON ML.RECORD_KEY = IM.MODIFIER_LIST_RECORD_KEY
LEFT JOIN [dbo].[MODIFIER_GROUP] MG ON MG.MODIFIER_LIST_RECORD_KEY = ML.RECORD_KEY
LEFT JOIN [dbo].[MODIFIER] M ON M.MODIFIER_GROUP_RECORD_KEY = MG.RECORD_KEY
CROSS APPLY DBO.parsePrice(I.PRICING) p

/*where ml.name is not null*/
order by 'ITEM CATEGORY','ITEM NAME',P."Price TYPE",P."Price LEVEL"

Tabled_Valued 函数

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE function [dbo].[parsePrice](@x xml)
returns table
return
select "PRICE TYPE","PRICE LEVEL",coalesce(try_cast("Item Price" as decimal(9,2)),0) "ITEM PRICE"
from (
   select t.n.value('@type','varchar(100)') "PRICE TYPE",p.n.value('@level','varchar(100)') "PRICE LEVEL",'nvarchar(50)') "ITEM PRICE"
   from @x.nodes('//prices') t(n),@x.nodes('prices/item') p(n)
) t