我正在尝试搜索存储在varchar(max)列中的xml数据 下面是varchar列中找到的一个xml数据字符串的示例 在这个例子中,我将使用名为@dsName的sql变量,当它的值与@dsName匹配时,它将与节点匹配,并且它从属于节点或从属节点。您之间或之前的节点可能会有所不同。
<business_process>
<ProcessDefinition name="dawns test">
<StartState name="START" uniqueId="Node3304">
<Transition name="Node4532" to="Node4532"/>
</StartState>
<EndState name="END4694" uniqueId="Node4694"/>
<User name="Node4532" uniqueId="Node4532">
<Description>test</Description>
<Distribution config-type="field" type="CommonQueueDistribution">
<Priority>0</Priority>
<AutoCompleteJob>false</AutoCompleteJob>
<GroupId>Admin</GroupId>
<UseAttendance>false</UseAttendance>
<UseShifts>false</UseShifts>
<NotifyActors>false</NotifyActors>
</Distribution>
<DocFinityTask type="DocFinityTask">
<description>read e-mail and approve or deny</description>
<help/>
<required>false</required>
<redoable>false</redoable>
<condition/>
<properties>
<undoable>true</undoable>
</properties>
</DocFinityTask>
<DocFinityTask type="SimpleFormTask">
<description>lob lookup</description>
<help/>
<required>false</required>
<redoable>true</redoable>
<condition/>
<properties>
<autoRun>true</autoRun>
<form>
<title>lob</title>
<formElement>
<type>Combobox</type>
<variable>lob</variable>
<tooltip>lob lookup</tooltip>
<label>lob</label>
<required>false</required>
<prepopulateValues>
<datasourceName>lob lookup</datasourceName>
</prepopulateValues>
<userEnter>true</userEnter>
<dataType>STRING</dataType>
</formElement>
</form>
</properties>
</DocFinityTask>
<Transition name="Node128795" to="Node128795"/>
</User>
<Server name="Node128795" uniqueId="Node128795">
<Description/>
<Event type="node-enter">
<Action type="SetProcessInstancePropertyAction" config-type="field">
<description>Whatever</description>
<propertyName>source</propertyName>
<datasourceName>get datasource list</datasourceName>
</Action>
</Event>
<Transition name="Node4694" to="END4694"/>
</Server>
<Server name="Node250" uniqueId="Node250">
<Description />
<Event type="node-enter">
<Action type="SetProcessInstancePropertyAction" config-type="field">
<description>Whatever</description>
<propertyName>source</propertyName>
<datasourceName>stump</datasourceName>
</Action>
</Event>
<Transition name="Node4694" to="END4694" />
</Server>
</ProcessDefinition>
<Layout>
<annotations/>
<nodes>
<node name="START" uniqueId="Node3304" type="startNode" text="START" x="184.5" y="135.5" width="25" height="25"/>
<node name="END4694" uniqueId="Node4694" type="endNode" text="END4694" x="588.5" y="137.5" width="25" height="25"/>
<node name="Node4532" uniqueId="Node4532" type="userNode" text="Node4532" info="false" x="296" y="135" width="150" height="50"/>
<node name="Node128795" uniqueId="Node128795" type="serverNode" text="Node128795" info="false" x="286" y="244" width="150" height="50"/>
</nodes>
<edges>
<edge originNode="Node3304" targetNode="Node4532" text="" sketch="arrow"/>
<edge originNode="Node4532" targetNode="Node128795" text="" sketch="arrow"/>
<edge originNode="Node128795" targetNode="Node4694" text="" sketch="arrow"/>
</edges>
</Layout>
这是我在尝试加载到XML数据类型的变量时使用的选择的示例。 varchar(max)列名称是XML
DECLARE @xml XML=
(SELECT [XML]
FROM ProcessModels
WHERE [XML] LIKE '%<datasourceName>' + @dsName + '%'
and [status] = 'ACTIVE')
如果将SQL加载到表变量中并且已经使用要搜索的字符串设置了@dsName变量,那么SQL select是相同的。
在这个例子中,我想找到每个服务器节点和/或用户节点的名称,当它有一个值为&#39;获取数据源列表的节点时。字符串&#39;获取数据源列表&#39;已经存在于变量@dsName。
中以下查询让我走了一半。
select sn.value('@name', 'varchar(100)') AS ServerNodes
from @xml.nodes('/business_process/ProcessDefinition/Server') AS ServerNodes(sn)
现在我需要弄清楚如何限制Server。@ name返回到子节点// datasourceName值等于sql:variable的那些。
这有效:
SELECT ServerNode.value('@name','varchar(max)') AS ServerNode
FROM @xml.nodes('/business_process/ProcessDefinition') AS ProcessDefinition(pd)
OUTER APPLY pd.nodes('Server[Event//datasourceName=sql:variable("@searchVariable")]') AS The(ServerNode)
WHERE ServerNode.value('@name','varchar(max)') IS NOT NULL
SELECT UserNode.value('@name','varchar(max)') AS UserNode
FROM @xml.nodes('/business_process/ProcessDefinition') AS ProcessDefinition(pd)
OUTER APPLY pd.nodes('User[DocFinityTask//datasourceName=sql:variable("@searchVariable")]') AS The(UserNode)
WHERE UserNode.value('@name','varchar(max)') IS NOT NULL
答案 0 :(得分:2)
您的朋友是sql:variable()
,如果您的搜索值来自表格列,也会有sql:column()
。
根据您的评论,我使用类型为varchar
的XML列模拟了一个表。 SELECT
将首先使用CROSS APPLY
将其转换为&#34;真实&#34; XML,然后.exist()
用于获取满足您条件的行,最后返回/User/@name
的值。
如果您将查找变量更改为&#34;另一个&#34;您将找到其他XML,其他字符串将返回空白。
作为XPath的示例,我给出了三个返回相同的查询。这取决于您的XML ......
DECLARE @tbl TABLE(ID INT IDENTITY, YourXMLAsVarchar VARCHAR(MAX));
INSERT INTO @tbl VALUES
('<User name="First Node" uniqueId="1332">
<Task type="Form">
<properties>
<form>
<formElement>
<populateValues>
<source>lookup</source>
</populateValues>
</formElement>
</form>
</properties>
</Task>
</User>')
,('<User name="First Node" uniqueId="1332">
<Task type="Form">
<properties>
<form>
<formElement>
<populateValues>
<source>another</source>
</populateValues>
</formElement>
</form>
</properties>
</Task>
</User>');
--Search for "lookup"
DECLARE @SearchingFor VARCHAR(100)='lookup';
--Search with full path
SELECT x.value('(/User/@name)[1]','varchar(max)')
FROM @tbl AS tbl
CROSS APPLY(SELECT CAST(YourXMLAsVarchar AS XML)) AS a(x)
WHERE x.exist('/User/Task/properties/form/formElement/populateValues/source[.=sql:variable("@SearchingFor")]')=1
--shorter, if there is not other "source" element this could be muddled up with...
SELECT x.value('(/User/@name)[1]','varchar(max)')
FROM @tbl AS tbl
CROSS APPLY(SELECT CAST(YourXMLAsVarchar AS XML)) AS a(x)
WHERE x.exist('//source[.=sql:variable("@SearchingFor")]')=1
--even shorter, if your lookup string won't be anywhere else an element's value
SELECT x.value('(/User/@name)[1]','varchar(max)')
FROM @tbl AS tbl
CROSS APPLY(SELECT CAST(YourXMLAsVarchar AS XML)) AS a(x)
WHERE x.exist('//*[.=sql:variable("@SearchingFor")]')=1
答案 1 :(得分:2)
因为我的第一个答案已经非常拥挤......
通过这种方式,您可以从XML中获取用户和服务器的数据。如果将@searchVariable
设置为不存在的datasourceName-value,则用户数据仍然存在,但Server数据将为NULL。试试吧!
DECLARE @xml XML=
'<business_process>
<ProcessDefinition name="dawns test">
<StartState name="START" uniqueId="Node3304">
<Transition name="Node4532" to="Node4532" />
</StartState>
<EndState name="END4694" uniqueId="Node4694" />
<User name="Node4532" uniqueId="Node4532">
<Description>test</Description>
<Distribution config-type="field" type="CommonQueueDistribution">
<Priority>0</Priority>
<AutoCompleteJob>false</AutoCompleteJob>
<GroupId>Admin</GroupId>
<UseAttendance>false</UseAttendance>
<UseShifts>false</UseShifts>
<NotifyActors>false</NotifyActors>
</Distribution>
<DocFinityTask type="DocFinityTask">
<description>read e-mail and approve or deny</description>
<help />
<required>false</required>
<redoable>false</redoable>
<condition />
<properties>
<undoable>true</undoable>
</properties>
</DocFinityTask>
<DocFinityTask type="SimpleFormTask">
<description>lob lookup</description>
<help />
<required>false</required>
<redoable>true</redoable>
<condition />
<properties>
<autoRun>true</autoRun>
<form>
<title>lob</title>
<formElement>
<type>Combobox</type>
<variable>lob</variable>
<tooltip>lob lookup</tooltip>
<label>lob</label>
<required>false</required>
<prepopulateValues>
<datasourceName>lob lookup</datasourceName>
</prepopulateValues>
<userEnter>true</userEnter>
<dataType>STRING</dataType>
</formElement>
</form>
</properties>
</DocFinityTask>
<Transition name="Node128795" to="Node128795" />
</User>
<Server name="Node128795" uniqueId="Node128795">
<Description />
<Event type="node-enter">
<Action type="SetProcessInstancePropertyAction" config-type="field">
<description>Whatever</description>
<propertyName>source</propertyName>
<datasourceName>get datasource list</datasourceName>
</Action>
</Event>
<Transition name="Node4694" to="END4694" />
</Server>
</ProcessDefinition>
<Layout>
<annotations />
<nodes>
<node name="START" uniqueId="Node3304" type="startNode" text="START" x="184.5" y="135.5" width="25" height="25" />
<node name="END4694" uniqueId="Node4694" type="endNode" text="END4694" x="588.5" y="137.5" width="25" height="25" />
<node name="Node4532" uniqueId="Node4532" type="userNode" text="Node4532" info="false" x="296" y="135" width="150" height="50" />
<node name="Node128795" uniqueId="Node128795" type="serverNode" text="Node128795" info="false" x="286" y="244" width="150" height="50" />
</nodes>
<edges>
<edge originNode="Node3304" targetNode="Node4532" text="" sketch="arrow" />
<edge originNode="Node4532" targetNode="Node128795" text="" sketch="arrow" />
<edge originNode="Node128795" targetNode="Node4694" text="" sketch="arrow" />
</edges>
</Layout>
</business_process>';
DECLARE @searchVariable VARCHAR(100)='get datasource list';
SELECT ServerNode.value('@name','varchar(max)') AS ServerName
,ServerNode.value('@uniqueId','varchar(max)') AS ServerId
,pd.value('User[1]/@name','varchar(max)') AS UserName
,pd.value('User[1]/@uniqueId','varchar(max)') AS UserId
FROM @xml.nodes('/business_process/ProcessDefinition') AS ProcessDefinition(pd)
OUTER APPLY pd.nodes('Server[Event/Action/datasourceName=sql:variable("@searchVariable")]') AS The(ServerNode);
答案 2 :(得分:1)
另一种选择。这并没有使用XML.exist
,但直接查找具有<source>
元素和查找变量的User元素。然后将路径反转回祖先User
并选择name
属性。
DECLARE @xml XML=
'<User name="First Node" uniqueId="1332">
<Task type="Form">
<properties>
<form>
<formElement>
<populateValues>
<source>lookup</source>
</populateValues>
</formElement>
</form>
</properties>
</Task>
</User>';
DECLARE @lookup NVARCHAR(128)='lookup';
SELECT
n.v.value('../../../../../../@name','NVARCHAR(128)') AS name
FROM
@xml.nodes('//User/Task/properties/form/formElement/populateValues/source[.=sql:variable("@lookup")]') AS n(v);
显然不支持XPath轴(至少在SQL Server 2012上不支持)。如果它不是../../../../../../@name
,那么您可以写出更简单的ancestor::User/@name
。