我的任务是调查一个黑盒子的替代解决方案'这个过程需要花费大量时间,但我们无法在其中改变或改进。
我要做的是从表中提取XML信息,当前它作为文本字段保存(使用CAST进行转换)。有多行,XML包含许多包含属性的嵌套元素。
为一行存储的XML的一个示例如下:
<offerContext weightExpr="90">
<filter label="Description of XML held here">
<where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488">
<condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" />
<condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = '1'" internalId="1370600592" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = 'Spend20get5Off'" internalId="1370600644" />
<condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" />
</condition>
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = 'Spend20get5Off'" internalId="1372382779" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate >= DaysAgo(21)" internalId="1372382782" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" />
</condition>
</where>
<humanCond>Query: Description of XML held here</humanCond>
</filter>
<extension useBuildPropositionsScript="false" />
</offerContext>
我需要提取的是来自offerContext元素的weightexpr。除此之外,我需要来自每个条件元素的booloperator,compositekey,dependkey,expr和internalId。我需要提取这些,以便子元素链接到它们的父元素,这是我遇到一些困难的地方。我有以下内容将两个元素拉成一行,但这会需要一些操作(我没有问题,但想知道是否有更好的方法),因为父条件元素重复多次。
我到目前为止的代码是:
;WITH contexts AS
(
SELECT a.iOfferId, a.iOfferContextId, a.mdata, CONVERT(xml,a.mdata) AS XMLmData
FROM NmsOfferContext a
)
SELECT
iOfferId
,iOfferContextId
,p2.value('(@weightExpr)[1]', 'nvarchar(max)' ) AS dweight
,p2.value('(@boolOperator)[1]', 'nvarchar(max)' ) AS boolOperator2
,p2.value('(@dependKey)[1]', 'nvarchar(max)' ) AS dependKey2
,p2.value('(@expr)[1]', 'nvarchar(max)' ) AS expr2
,p2.value('(@setOperator)[1]', 'nvarchar(max)' ) AS setoperator2
,p2.value('(@internalId)[1]', 'nvarchar(max)' ) AS internalID2
,p3.value('(@boolOperator)[1]', 'nvarchar(max)' ) AS boolOperator3
,p3.value('(@dependKey)[1]', 'nvarchar(max)' ) AS dependKey3
,p3.value('(@expr)[1]', 'nvarchar(max)' ) AS expr3
,p3.value('(@setOperator)[1]', 'nvarchar(max)' ) AS setoperator3
,p3.value('(@internalId)[1]', 'nvarchar(max)' ) AS internalID3
FROM contexts
CROSS APPLY XMLmData.nodes('/offerContext/*/*/condition') t(p2)
CROSS APPLY XMLmData.nodes('/offerContext/*/*/condition/condition') t2(p3)
ORDER BY iOfferContextId,
p2.value('(@internalId)[1]', 'nvarchar(max)' ),
p3.value('(@internalId)[1]', 'nvarchar(max)' )
最终我需要根据expr值构造SQL查询并使用booloperator作为WHERE子句,因此为什么我对元素有正确的顺序很重要(我相信我也可以使用internalId属性实现)但保留父母和孩子之间的关系是我需要帮助的地方。
如果我走在正确的轨道上,任何帮助都会受到赞赏和肯定。如果有什么需要更明确的解释,请随时提出。
提前致谢。
答案 0 :(得分:2)
您可以使用递归CTE来分解XML,以构建节点级别之间的关系。
declare @X xml = '
<offerContext weightExpr="90">
<filter label="Description of XML held here">
<where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488">
<condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" />
<condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = ''1''" internalId="1370600592" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1370600644" />
<condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" />
</condition>
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1372382779" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate >= DaysAgo(21)" internalId="1372382782" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" />
</condition>
</where>
<humanCond>Query: Description of XML held here</humanCond>
</filter>
<extension useBuildPropositionsScript="false" />
</offerContext>';
with A as
(
select T.X.value('@weightExpr', 'int') as weightExpr,
T.X.query('filter/where/condition') as C,
cast(null as int) as internalID,
cast(null as int) as internalParentID,
cast(null as varchar(10)) as boolOperator,
cast(null as varchar(20)) as dependKey,
cast(null as varchar(50)) as expr
from @X.nodes('/offerContext') as T(X)
union all
select null,
T.X.query('condition'),
T.X.value('@internalId', 'int'),
A.internalID,
T.X.value('@boolOperator', 'varchar(10)'),
T.X.value('@dependkey', 'varchar(100)'),
T.X.value('@expr', 'varchar(100)')
from A
cross apply A.C.nodes('condition') as T(X)
)
select A.weightExpr,
A.internalID,
A.internalParentID,
A.boolOperator,
A.dependKey,
A.expr
from A
order by A.internalID
结果:
weightExpr internalID internalParentID boolOperator dependKey expr
---------- ----------- ---------------- ------------ ------------- --------------------------------
90 NULL NULL NULL NULL NULL
NULL -1548698833 NULL AND FK_Rcp_Brand @BrandId = 1
NULL 1370600592 NULL AND FK_Rcp_Brand = '1'
NULL 1370600625 NULL AND proposition
NULL 1370600632 1370600625 AND @status = 3
NULL 1370600644 1370600625 AND [offer/@name] = 'Spend20get5Off'
NULL 1370600655 1370600625 NULL [offerSpace/@channel] = 0
NULL 1372382776 NULL AND proposition
NULL 1372382779 1372382776 AND [offer/@name] = 'Spend20get5Off'
NULL 1372382782 1372382776 AND @eventDate >= DaysAgo(21)
NULL 1372382786 1372382776 AND [offerSpace/@channel] = 0
当源是表时重写。
with A as
(
select Y.offerID,
T.X.value('@weightExpr', 'int') as weightExpr,
T.X.query('filter/where/condition') as C,
cast(null as int) as internalID,
cast(null as int) as internalParentID,
cast(null as varchar(10)) as boolOperator,
cast(null as varchar(20)) as dependKey,
cast(null as varchar(50)) as expr
from dbo.YourTable as Y
cross apply Y.X.nodes('/offerContext') as T(X)
union all
select A.offerID,
null,
T.X.query('condition'),
T.X.value('@internalId', 'int'),
A.internalID,
T.X.value('@boolOperator', 'varchar(10)'),
T.X.value('@dependkey', 'varchar(20)'),
T.X.value('@expr', 'varchar(50)')
from A
cross apply A.C.nodes('condition') as T(X)
)
select A.offerID,
A.weightExpr,
A.internalID,
A.internalParentID,
A.boolOperator,
A.dependKey,
A.expr
from A
order by A.offerID,
A.internalID
答案 1 :(得分:1)
这是另一种方法,可能比递归方法更容易。这是基于OP的评论,至少目前 - 至少不超过2个级别。
在第一步中,第一级的条件被采用,他们的内部第二级条件按。它们按照它们出现的顺序编号。
在第二阶段,采取第二级的条件。它们的出现顺序再次编号,由父母划分。
最后两个选择被联合并按条件的位置排序:
DECLARE @xml XML=
'<offerContext weightExpr="90">
<filter label="Description of XML held here">
<where displayFilter="Second description of XML held here" filterName="backGroundFilterFrm" id="13706004488">
<condition boolOperator="AND" compositeKey="" dependkey="FK_Rcp_Brand" enabledIf="" expr="@BrandId = 1" internalId="-1548698833" />
<condition boolOperator="AND" compositeKey="FK_Rcp_Brand" dependkey="" expr="FK_Rcp_Brand = ''1''" internalId="1370600592" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="proposition" internalId="1370600625" setOperator="EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" expr="@status = 3" internalId="1370600632" />
<condition boolOperator="AND" compositeKey="" dependkey="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1370600644" />
<condition compositeKey="" dependkey="" expr="[offerSpace/@channel] = 0" internalId="1370600655" />
</condition>
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="proposition" internalId="1372382776" setOperator="NOT EXISTS">
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offer/@name] = ''Spend20get5Off''" internalId="1372382779" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="@eventDate >= DaysAgo(21)" internalId="1372382782" />
<condition boolOperator="AND" compositeKey="" dependkey="" enabledIf="" expr="[offerSpace/@channel] = 0" internalId="1372382786" />
</condition>
</where>
<humanCond>Query: Description of XML held here</humanCond>
</filter>
<extension useBuildPropositionsScript="false" />
</offerContext>';
WITH AllConditionsLevel1 AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS CondLevel1_Position
,CAST(0 AS BIGINT) AS CondLevel2_Position
,1 AS CondLevel
,@xml.value('(offerContext/@weightExpr)[1]','int') AS OfferContext_WeightExpr
,@xml.value('(offerContext/filter/@label)[1]','varchar(max)') AS Filter_Label
,@xml.value('(offerContext/where/@displayFilter)[1]','varchar(max)') AS Where_DisplayFilter
,@xml.value('(offerContext/where/@filterName)[1]','varchar(max)') AS Where_FilterName
,@xml.value('(offerContext/where/@id)[1]','varchar(max)') AS Where_Id
,CondLevel1.value('@boolOperator','varchar(max)') AS Cond_BoolOperator
,CondLevel1.value('@compositeKey','varchar(max)') AS Cond_CompositeKey
,CondLevel1.value('@dependkey','varchar(max)') AS Cond_DependKey
,CondLevel1.value('@expr','varchar(max)') AS Cond_Expr
,CondLevel1.value('@internalId','varchar(max)') AS Cond_InternalId
,CondLevel1.value('@setOperator','varchar(max)') AS Cond_SetOperator
,CondLevel1.value('@enabledIf','varchar(max)') AS Cond_EnabledIf
,CondLevel1.query('*') AS CondLevel2Nodes
FROM @xml.nodes('offerContext/filter/where/condition') AS A(CondLevel1)
)
SELECT *
FROM
(
SELECT * FROM AllConditionsLevel1
UNION ALL
SELECT CondLevel1_Position
,ROW_NUMBER() OVER(PARTITION BY CondLevel1_Position ORDER BY (SELECT NULL))
,2
,OfferContext_WeightExpr
,Filter_Label
,Where_DisplayFilter
,Where_FilterName
,Where_Id
,CondLevel2.value('@boolOperator','varchar(max)')
,CondLevel2.value('@compositeKey','varchar(max)')
,CondLevel2.value('@dependkey','varchar(max)')
,CondLevel2.value('@expr','varchar(max)')
,CondLevel2.value('@internalId','varchar(max)')
,CondLevel2.value('@setOperator','varchar(max)')
,CondLevel2.value('@enabledIf','varchar(max)')
,NULL
FROM AllConditionsLevel1
CROSS APPLY CondLevel2Nodes.nodes('condition') AS B(CondLevel2)
) AS tbl
ORDER BY CondLevel1_Position,CondLevel2_Position