我有一个SQL Server 2014数据库,可存储200万个XML文件。 XML文件如下所示:
<?xml version='1.0' encoding='UTF-16'?>
<PROJECTS xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
<row>
<APPLICATION_ID>7975883</APPLICATION_ID>
<ACTIVITY>N01</ACTIVITY>
<ADMINISTERING_IC>HL</ADMINISTERING_IC>
<APPLICATION_TYPE xsi:nil="true"/>
<ARRA_FUNDED>N</ARRA_FUNDED>
<PIS>
<PI>
<PI_NAME>MICHEL, MARY Q</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
<PI>
<PI_NAME>SMITH, ROBERT B</PI_NAME>
<PI_ID>3704354</PI_ID>
</PI>
<PI>
<PI_NAME>DOE, JOHN A</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
</PIS>
<ORG_DUNS>600044978</ORG_DUNS>
<ORG_COUNTRY>UNITED STATES</ORG_COUNTRY>
<ORG_DISTRICT>08</ORG_DISTRICT>
<ORG_ZIPCODE>208523003</ORG_ZIPCODE>
</row>
</PROJECTS>
我的问题是我想根据存储过程中的ORG_DUNS
数字提取所有PI值。所以我的代码是:
SELECT
APPLICATION_ID,
nref.value('.','varchar(max)') TERM
INTO
ADMIN_MUSC_RePORTER_TERMS
FROM
[ADMIN_Grant_Exporter_Files_XML]
CROSS APPLY
XMLData.nodes('//PIS/PI') AS R(nref)
WHERE
RECID = 1
当我使用WHERE导致基于数据库中的另一个字段但是如果我需要在xml文件中引用我遇到问题的节点时工作正常。我需要提取ORG_DUNS等于600044978的所有XML文件,并且我知道由于交叉应用,nref.value('ORG_DUNS[1]', 'varchar(max)')
不存在。
SELECT
APPLICATION_ID,
nref.value('.','varchar(max)') TERM
INTO
ADMIN_MUSC_RePORTER_TERMS
FROM
[ADMIN_Grant_Exporter_Files_XML]
CROSS APPLY
XMLData.nodes('//PIS/PI') as R(nref)
WHERE
nref.value('ORG_DUNS[1]', 'varchar(max)') = '600044978'
那么如何使用ORG_DUNS作为我的WHERE来获取所有PI节点?感谢
答案 0 :(得分:2)
更改Cross Apply语句以在XPath中包含过滤器逻辑:
CROSS APPLY XMLData.nodes('//PIS[../ORG_DUNS/text() = ''600044978'']/PI') AS R(nref)
要解释一下,//PIS[../ORG_DUNS/text() = ''600044978'']/PI
说:
//PIS
- 找到所有名为PIS的元素[
... ]
- 为符合此条件的人筛选返回的元素../ORG_DUNS/text() = ''600044978''
- 条件:PIS
的父元素ORG_DUNS
的文字值等于600044978
。PI
元素的子PIS
元素。每条评论更新
完整SQL,包括PI和PI_ID作为单独的值:
SELECT
APPLICATION_ID
, nref.value('(./PI_NAME/text())[1]','varchar(max)') PI
, nref.value('(./PI_ID/text())[1]','varchar(max)') PI_ID
INTO
ADMIN_MUSC_RePORTER_TERMS
FROM
[ADMIN_Grant_Exporter_Files_XML]
CROSS APPLY
XMLData.nodes('//PIS[../ORG_DUNS/text() = ''600044978'']/PI') AS R(nref)
WHERE
RECID = 1
注意:
./PI_NAME
- 从当前选定的元素(即nref
列引用的元素;指向PI
元素),获取其子元素{{1 }}。PI_NAME
- 从/text()
元素中获取其子文本元素(严格来说,这不是必需的,因为当拉回值并转换为varchar时,我们会得到相同的内容结果;但我喜欢明确)。PI_NAME
... (
- 返回单身人士。即使当前)[1]
下有多个PI_NAME
元素,我们只需要返回1个值。通过在我们的表达式周围加上括号,我们对这个表达式返回的所有值&#34;&#34 ;;并且PI
表示取第一个结果(因为XPATH使用基于一个的索引而不是基于零的索引,因为大多数其他语言会这样做。)使用变量过滤
预测你的下一期; ie&#34;如何在不构建动态SQL的情况下在运行时更改数量?&#34;,使用sql:variable函数的答案:
[1]
答案 1 :(得分:1)
这里的技巧是首先使用多个CROSS APPLY子句在文档中抓取多个级别。首先,从根目录开始抓取所有&#39; / PROJECTS / row&#39;然后使用每个&#39; PIS / PI&#39;
中的相对路径像这样:
declare @t table(id int identity, APPLICATION_ID int default (2), XmlData xml)
insert into @t(XmlData) values (
'<PROJECTS xmlns:xsi=''http://www.w3.org/2001/XMLSchema-instance''>
<row>
<APPLICATION_ID>7975883</APPLICATION_ID>
<ACTIVITY>N01</ACTIVITY>
<ADMINISTERING_IC>HL</ADMINISTERING_IC>
<APPLICATION_TYPE xsi:nil="true"/>
<ARRA_FUNDED>N</ARRA_FUNDED>
<PIS>
<PI>
<PI_NAME>MICHEL, MARY Q</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
<PI>
<PI_NAME>SMITH, ROBERT B</PI_NAME>
<PI_ID>3704354</PI_ID>
</PI>
<PI>
<PI_NAME>DOE, JOHN A</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
</PIS>
<ORG_DUNS>600044978</ORG_DUNS>
<ORG_COUNTRY>UNITED STATES</ORG_COUNTRY>
<ORG_DISTRICT>08</ORG_DISTRICT>
<ORG_ZIPCODE>208523003</ORG_ZIPCODE>
</row>
</PROJECTS> '),(
'<PROJECTS xmlns:xsi=''http://www.w3.org/2001/XMLSchema-instance''>
<row>
<APPLICATION_ID>7975883</APPLICATION_ID>
<ACTIVITY>N01</ACTIVITY>
<ADMINISTERING_IC>HL</ADMINISTERING_IC>
<APPLICATION_TYPE xsi:nil="true"/>
<ARRA_FUNDED>N</ARRA_FUNDED>
<PIS>
<PI>
<PI_NAME>MICHEL, MARY Q</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
<PI>
<PI_NAME>SMITH, ROBERT B</PI_NAME>
<PI_ID>3704354</PI_ID>
</PI>
<PI>
<PI_NAME>DOE, JOHN A</PI_NAME>
<PI_ID>3704353</PI_ID>
</PI>
</PIS>
<ORG_DUNS>600044979</ORG_DUNS>
<ORG_COUNTRY>UNITED STATES</ORG_COUNTRY>
<ORG_DISTRICT>08</ORG_DISTRICT>
<ORG_ZIPCODE>208523003</ORG_ZIPCODE>
</row>
</PROJECTS> ')
select APPLICATION_ID,
pinode.value('PI_NAME[1]','varchar(max)') PI_NAME,
pinode.value('PI_ID[1]','varchar(max)') PI_ID
FROM @t
cross apply XMLData.nodes('/PROJECTS/row') as r(rownode)
cross apply rownode.nodes('PIS/PI') as p(pinode)
where rownode.value('ORG_DUNS[1]','varchar(max)') = '600044978'