我正在使用供应商的数据库,其中包含一些XML数据:
<ArrayOfAlertConditionShelve xmlns="http://schemas.datacontract.org/2004/07/VendorName.Alerting" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AlertConditionShelve>
<AndThenTimeInterval i:nil="true" />
<ChainType>Trigger</ChainType>
<ConditionTypeID>Core.Dynamic</ConditionTypeID>
<Configuration>
<AlertConditionDynamic xmlns="http://schemas.datacontract.org/2004/07/VendorName.Dynamic" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ExprTree xmlns:a="http://schemas.datacontract.org/2004/07/VendorName.Alerting">
<a:Child>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ApplicationAlert|ApplicationName|Application.ApplicationAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>AppNameABC123</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>NodesCustomProperties|n_mute|Application.Node.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>false</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ApplicationCustomProperties|a_mute|Application.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>false</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>NodesCustomProperties|Prod_State|Application.Node.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>PROD</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>Down</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>Critical</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>OR</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>AND</a:Value>
</ExprTree>
<Scope xmlns:a="http://schemas.datacontract.org/2004/07/VendorName.Alerting" i:nil="true" />
<TimeWindow i:nil="true" />
</AlertConditionDynamic>
</Configuration>
<ConjunctionOperator>None</ConjunctionOperator>
<IsInvertedMinCountThreshold>false</IsInvertedMinCountThreshold>
<NetObjectsMinCountThreshold i:nil="true" />
<ObjectType>APM: Component</ObjectType>
<SustainTime>PT5M</SustainTime>
</AlertConditionShelve>
</ArrayOfAlertConditionShelve>
我的要求是为每个“a:NodeType”元素返回“a:value”元素的值。另外,我需要管道之间的字符串{| |在“a:NodeType”元素中,虽然如果它过多地混淆了这个解决方案,我可以用子串来获得它。
我还需要查看“ObjectType”和“SustainTime”元素的值。为了增加更多的复杂性,“SustainTime”元素并不总是存在。
我已经通过StackOverflow和几个搜索各种网站和博客的一般谷歌搜索进行了相当多的搜索,但不幸的是我似乎无法将不同的部分放在一起。
作为参考,这是我在上面的例子中寻找的结果:
+-----------------------+----------+----------------+
| NodeType | Operator | Value |
+-----------------------+----------+----------------+
| ApplicationName | = | AppNameABC123 |
| n_mute | = | false |
| a_mute | = | false |
| ProdState | = | PROD |
| ComponentAvailability | = | Critical |
| ComponentAvailability | = | Down |
| ObjectType | | APM: Component |
| SustainTime | | PT5M |
+-----------------------+----------+----------------+
几个笔记:
这是与此XML
匹配的关联SQL查询的示例SELECT * FROM Table
WHERE ( ApplicationName = 'AppNameABC123' AND n_mute = 0 AND a_mute = 0 AND ProdState = 'PROD')
AND ( ComponentAvailability = 'Critical' OR ComponentAvailability = 'Down' )
我感谢任何帮助或指导!作为一项规则,我对SQL Server查询非常认真,但至少可以说,潜入XML已经令人羞愧。
修改
在找到一篇对我的大脑更有意义的文章后,我取得了一些进展:
https://www.red-gate.com/simple-talk/sql/learn-sql-server/the-xml-methods-in-sql-server/
-- exist() Method
-- DbObject.exist('XQuery')
-- 1 if the XQuery expression returns a nonempty result
-- 0 if the XQuery expression returns an empty result.
-- NULL value if the XML data type instance is null.
SELECT
v.AlertID
,v.alertTriggerQuery.value(
'(/*:Expr/*:NodeType) [1]','varchar(max)'
) 'alertTriggerQueryNodeTypeValue'
,v.alertTriggerQuery.value(
'(/*:Expr/*:Value) [1]','varchar(max)'
) 'alertTriggerQueryValue'
,v.objectType.value(
'(/*:ObjectType) [1]', 'varchar(100)'
) 'alertTriggerValue'
,v.sustainTime.value(
'(/*:SustainTime) [1]', 'varchar(10)'
) 'sustainTimeValue'
,v.sustainTime.value('concat("TRIGGER DELAY: ",
(/*:SustainTime) [1])', 'varchar(100)'
) 'sustainTimeValueConcat'
FROM
(SELECT
q.AlertID
,q.triggerXML.query('
/*:ArrayOfAlertConditionShelve/*:AlertConditionShelve/*:Configuration/*:AlertConditionDynamic/*:ExprTree/*:Child/*:Expr/*:Child/*:Expr
') 'alertTriggerQuery'
,q.triggerXML.query('
/*:ArrayOfAlertConditionShelve/*:AlertConditionShelve/*:ObjectType
') 'objectType'
,q.triggerXML.query('
/*:ArrayOfAlertConditionShelve/*:AlertConditionShelve/*:SustainTime
') 'sustainTime'
FROM (
SELECT
AlertID
,CAST(REPLACE(REPLACE([Trigger],'<','<'),'>','>') AS XML) 'triggerXML'
FROM AlertConfigurations
WHERE AlertID IN ( 280, 3052 )
) q
WHERE q.triggerXML.exist('/*:ArrayOfAlertConditionShelve/*:AlertConditionShelve[*:SustainTime="PT5M"]') = 1
) v;
GO
使用query(),value()和exist()方法的组合,我已经能够深入研究XML并获得以下数据:
+---------+--------------------------------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
| AlertID | alertTriggerQueryNodeTypeValue | alertTriggerQueryValue | alertTriggerValue | sustainTimeValue | sustainTimeValueConcat |
+---------+--------------------------------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
| 280 | Field | APM.ApplicationAlert|ApplicationName|Application.ApplicationAlert | APM:Component | PT5M | TRIGGER DELAY: PT5M |
+---------+--------------------------------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
所以,我认为下一步是弄清楚如何从我的subselect语句中的'alertTriggerQuery'XML中获取详细信息;看起来像这样:
<p1:Expr xmlns:p1="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p1:Child />
<p1:NodeType>Field</p1:NodeType>
<p1:Value>APM.ApplicationAlert|ApplicationName|Application.ApplicationAlert</p1:Value>
</p1:Expr>
<p2:Expr xmlns:p2="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p2:Child />
<p2:NodeType>Constant</p2:NodeType>
<p2:Value>WINWATCHER_WEB_02_URL</p2:Value>
</p2:Expr>
<p3:Expr xmlns:p3="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p3:Child />
<p3:NodeType>Field</p3:NodeType>
<p3:Value>NodesCustomProperties|n_mute|Application.Node.CustomProperties</p3:Value>
</p3:Expr>
<p4:Expr xmlns:p4="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p4:Child />
<p4:NodeType>Constant</p4:NodeType>
<p4:Value>false</p4:Value>
</p4:Expr>
<p5:Expr xmlns:p5="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p5:Child />
<p5:NodeType>Field</p5:NodeType>
<p5:Value>APM.ApplicationCustomProperties|a_mute|Application.CustomProperties</p5:Value>
</p5:Expr>
<p6:Expr xmlns:p6="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p6:Child />
<p6:NodeType>Constant</p6:NodeType>
<p6:Value>false</p6:Value>
</p6:Expr>
<p7:Expr xmlns:p7="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p7:Child />
<p7:NodeType>Field</p7:NodeType>
<p7:Value>NodesCustomProperties|Prod_State|Application.Node.CustomProperties</p7:Value>
</p7:Expr>
<p8:Expr xmlns:p8="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p8:Child />
<p8:NodeType>Constant</p8:NodeType>
<p8:Value>PROD</p8:Value>
</p8:Expr>
<p9:Expr xmlns:p9="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<p9:Child>
<p9:Expr>
<p9:Child />
<p9:NodeType>Field</p9:NodeType>
<p9:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</p9:Value>
</p9:Expr>
<p9:Expr>
<p9:Child />
<p9:NodeType>Constant</p9:NodeType>
<p9:Value>Down</p9:Value>
</p9:Expr>
</p9:Child>
<p9:NodeType>Operator</p9:NodeType>
<p9:Value>=</p9:Value>
</p9:Expr>
<pA:Expr xmlns:pA="http://schemas.datacontract.org/2004/07/VENDORNAME.Alerting">
<pA:Child>
<pA:Expr>
<pA:Child />
<pA:NodeType>Field</pA:NodeType>
<pA:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</pA:Value>
</pA:Expr>
<pA:Expr>
<pA:Child />
<pA:NodeType>Constant</pA:NodeType>
<pA:Value>Critical</pA:Value>
</pA:Expr>
</pA:Child>
<pA:NodeType>Operator</pA:NodeType>
<pA:Value>=</pA:Value>
</pA:Expr>
目前的障碍是弄清楚如何返回单个结果表,该表迭代“NodeType”和“Value”的每个父节点的值
即:
+---------+------+----------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
| AlertID | Node | NodeType | Value | alertTriggerValue | sustainTimeValue | sustainTimeValueConcat |
+---------+------+----------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
| 280 | p1 | Field | APM.ApplicationAlert|ApplicationName|Application.ApplicationAlert | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | p2 | Constant | WINWATCHER_WEB_02_URL | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | ... | ... | ... | ... | ... | ... |
| 280 | p9 | Field | APM.ComponentAlert|ComponentAvailability|ComponentAlert | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | p9 | Constant | Down | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | p9 | Operator | = | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | pA | Field | APM.ComponentAlert|ComponentAvailability|ComponentAlert | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | pA | Constant | Critical | APM:Component | PT5M | TRIGGER DELAY: PT5M |
| 280 | pA | Operator | = | APM:Component | PT5M | TRIGGER DELAY: PT5M |
+---------+------+----------+-------------------------------------------------------------------+-------------------+------------------+------------------------+
我相信我当前的限制是在我的“v.alertTriggerQuery.value()”语句中,我必须调出节点位置“[1]”。在PowerShell中,我会在将所有节点放入数组后执行与Foreach循环类似的操作;但我不确定如何将该逻辑转换为SQL。
答案 0 :(得分:2)
我很害怕... ...
DECLARE @yourTable TABLE(ID INT IDENTITY, TheXml XML);
INSERT INTO @yourTable VALUES
(N'<ArrayOfAlertConditionShelve xmlns="http://schemas.datacontract.org/2004/07/VendorName.Alerting" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AlertConditionShelve>
<AndThenTimeInterval i:nil="true" />
<ChainType>Trigger</ChainType>
<ConditionTypeID>Core.Dynamic</ConditionTypeID>
<Configuration>
<AlertConditionDynamic xmlns="http://schemas.datacontract.org/2004/07/VendorName.Dynamic" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ExprTree xmlns:a="http://schemas.datacontract.org/2004/07/VendorName.Alerting">
<a:Child>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ApplicationAlert|ApplicationName|Application.ApplicationAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>AppNameABC123</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>NodesCustomProperties|n_mute|Application.Node.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>false</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ApplicationCustomProperties|a_mute|Application.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>false</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>NodesCustomProperties|Prod_State|Application.Node.CustomProperties</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>PROD</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>Down</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
<a:Expr>
<a:Child>
<a:Expr>
<a:Child />
<a:NodeType>Field</a:NodeType>
<a:Value>APM.ComponentAlert|ComponentAvailability|ComponentAlert</a:Value>
</a:Expr>
<a:Expr>
<a:Child />
<a:NodeType>Constant</a:NodeType>
<a:Value>Critical</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>=</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>OR</a:Value>
</a:Expr>
</a:Child>
<a:NodeType>Operator</a:NodeType>
<a:Value>AND</a:Value>
</ExprTree>
<Scope xmlns:a="http://schemas.datacontract.org/2004/07/VendorName.Alerting" i:nil="true" />
<TimeWindow i:nil="true" />
</AlertConditionDynamic>
</Configuration>
<ConjunctionOperator>None</ConjunctionOperator>
<IsInvertedMinCountThreshold>false</IsInvertedMinCountThreshold>
<NetObjectsMinCountThreshold i:nil="true" />
<ObjectType>APM: Component</ObjectType>
<SustainTime>PT5M</SustainTime>
</AlertConditionShelve>
</ArrayOfAlertConditionShelve>');
- 一些一般提示:
--Easy-Cheesy: The two meta-data values
SELECT t.TheXml.value(N'(//*:ObjectType/text())[1]',N'nvarchar(max)') AS ObjectType
,t.TheXml.value(N'(//*:SustainTime/text())[1]',N'nvarchar(max)') AS SustainTime
FROM @yourTable AS t;
--Specified default namespace, full XPath
WITH XMLNAMESPACES(DEFAULT 'http://schemas.datacontract.org/2004/07/VendorName.Alerting')
SELECT t.TheXml.value(N'(/ArrayOfAlertConditionShelve/AlertConditionShelve/ObjectType/text())[1]',N'nvarchar(max)') AS ObjectType
,t.TheXml.value(N'(/ArrayOfAlertConditionShelve/AlertConditionShelve/SustainTime/text())[1]',N'nvarchar(max)') AS SustainTime
FROM @yourTable AS t
- 您可以使用//
的“深度搜索”来查找所有元素,但这实际上没有用处:
--Eays-Cheesy: All NodeTypes with their Values but not in the correct order and nesting
SELECT AnyExprWithNodeType.value(N'(*:NodeType/text())[1]',N'nvarchar(max)') AS NodeType
,AnyExprWithNodeType.value(N'(*:Value/text())[1]',N'nvarchar(max)') AS NodeValue
FROM @yourTable AS t
CROSS APPLY t.TheXml.nodes(N'//*:Expr[*:NodeType]') AS A(AnyExprWithNodeType);
- 尝试解决这个问题(没有更深的嵌套) - 这个工作直到“或”,其余部分更深层次嵌套。
WITH XMLNAMESPACES(DEFAULT 'http://schemas.datacontract.org/2004/07/VendorName.Alerting'
,'http://schemas.datacontract.org/2004/07/VendorName.Alerting' AS a
,'http://schemas.datacontract.org/2004/07/VendorName.Dynamic' AS innerDflt)
SELECT FirstLvlExpr.value(N'(a:Child//a:Expr[a:NodeType/text()="Field"]/a:Value/text())[1]','nvarchar(max)') AS NodeType
,FirstLvlExpr.value(N'(a:Value/text())[1]','nvarchar(max)') AS Operator
,FirstLvlExpr.value(N'(a:Child//a:Expr[a:NodeType/text()="Constant"]/a:Value/text())[1]','nvarchar(max)') AS Value
FROM @yourTable AS t
CROSS APPLY t.TheXml.nodes(N'/ArrayOfAlertConditionShelve
/AlertConditionShelve
/Configuration
/innerDflt:AlertConditionDynamic
/innerDflt:ExprTree
/a:Child
/a:Expr') AS A(FirstLvlExpr);
我认为,这样的树可能非常复杂并且层次结构嵌套。您可以使用递归CTE或某种重复CROSS APPLY
与.nodes()
来深入挖掘。
希望这会有所帮助......
以下语句将从<NodeType>
为 Field 的所有元素text()
开始。对.nodes()
的调用会从所有拟合节点创建派生表,无论它们在哪里。
下一步使用向后导航(..
)来爬上父母并找到相关的值和运算符。试试吧:
WITH XMLNAMESPACES(DEFAULT 'http://schemas.datacontract.org/2004/07/VendorName.Alerting'
,'http://schemas.datacontract.org/2004/07/VendorName.Alerting' AS a
,'http://schemas.datacontract.org/2004/07/VendorName.Dynamic' AS innerDflt)
SELECT B.NodeTypeSplitted
,B.NodeTypeSplitted.value(N'/*:x[2]/text()[1]',N'nvarchar(max)') AS SecondPartOfNodeType
,Fields.value(N'(../../../a:Value/text())[1]','nvarchar(max)') AS Operator
,Fields.value(N'(../../a:Expr[a:NodeType[text()="Constant"]]/a:Value/text())[1]','nvarchar(max)') AS NodeType
FROM @yourTable AS t
CROSS APPLY t.TheXml.nodes(N'//a:NodeType[text()="Field"]') AS A(Fields)
CROSS APPLY (SELECT CAST('<x>' + REPLACE((SELECT Fields.value(N'(../a:Value/text())[1]','nvarchar(max)') AS [*] FOR XML PATH('')),'|','</x><x>') + '</x>' AS XML) AS NodeTypeSplitted) AS B;
结果
SecondPartOfNodeType Operator NodeType
ApplicationName = AppNameABC123
n_mute = false
a_mute = false
Prod_State = PROD
ComponentAvailability = Down
ComponentAvailability = Critical
管道值的拆分是通过XML技巧完成的。