SQL Server 2019 存储过程中的 XML 节点需要一个 where 子句

Need a where clause for an XML Node in a SQL Server 2019 stored procedure

我有 150 万个 XML 文档存储在 SQL Server 2019 数据库中,我需要在存储过程中有一个包含多个节点的 where 子句。

<PROJECTS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
    <APPLICATION_ID>1015</APPLICATION_ID>
    <ORG_STATE>SC</ORG_STATE>
    <ORG_CITY>Charleston</ORG_CITY>
    <ORG_ZIPCODE>29407</ORG_ZIPCODE>
    <PIS>
      <PI>
        <PI_NAME>BO, LEO (contact)</PI_NAME>
        <PI_ID>9983950 (contact)</PI_ID>
      </PI>
      <PI>
        <PI_NAME>KUZ, BEN I</PI_NAME>
        <PI_ID>1862593</PI_ID>
      </PI>
    </PIS>
    <PROJECT_START>08/15/2019</PROJECT_START>
    <PROJECT_END>05/31/2024</PROJECT_END>
    <INDIRECT_COST_AMT>103034</INDIRECT_COST_AMT>
    <TOTAL_COST>638854</TOTAL_COST>
    <TOTAL_COST_SUB_PROJECT />
  </row>
</PROJECTS>

我需要提取 PI_ID 等于 9983950 的所有 XML 个文件。 PIS 节点中 PI 的数量可以是 1 个或 5 个。

我正在使用此代码:

SELECT TOP 100 
    [APPLICATION_ID], [FileName], [XMLData],
    nref.value('ORG_CITY[1]', 'VARCHAR(30)') as ORG_CITY  
FROM
    [NIH_EXPORTER].[dbo].[ADMIN_Exporter_Files_XML] 
CROSS APPLY
    XMLData.nodes('//row[1]') AS R(nref)
WHERE 
    nref.value('ORG_CITY[1]', 'VARCHAR(30)') = 'Charleston'

当我需要城市但我不确定在有多个节点时如何找到值

您可以检查是否存在任何需要的 PIS/PI 节点,并在链下使用 CROSS APPLY。

SELECT TOP 100 
    [APPLICATION_ID], [FileName], [XMLData],
    nref.value('ORG_CITY[1]', 'VARCHAR(30)') as ORG_CITY  
FROM
    [NIH_EXPORTER].[dbo].[ADMIN_Exporter_Files_XML] 
CROSS APPLY
    XMLData.nodes('//row[1]') AS R(nref)
--
cross apply (select top(1) null x
     from R.nref.nodes('./PIS/PI') t(n)
     where t.n.value('./PI_ID[1]', 'VARCHAR(30)') like '9983950%' ) t
--
WHERE 
    nref.value('ORG_CITY[1]', 'VARCHAR(30)') = 'Charleston'

请尝试以下解决方案。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<PROJECTS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <row>
        <APPLICATION_ID>1015</APPLICATION_ID>
        <ORG_STATE>SC</ORG_STATE>
        <ORG_CITY>Charleston</ORG_CITY>
        <ORG_ZIPCODE>29407</ORG_ZIPCODE>
        <PIS>
            <PI>
                <PI_NAME>BO, LEO (contact)</PI_NAME>
                <PI_ID>9983950 (contact)</PI_ID>
            </PI>
            <PI>
                <PI_NAME>KUZ, BEN I</PI_NAME>
                <PI_ID>1862593</PI_ID>
            </PI>
        </PIS>
        <PROJECT_START>08/15/2019</PROJECT_START>
        <PROJECT_END>05/31/2024</PROJECT_END>
        <INDIRECT_COST_AMT>103034</INDIRECT_COST_AMT>
        <TOTAL_COST>638854</TOTAL_COST>
        <TOTAL_COST_SUB_PROJECT/>
    </row>
</PROJECTS>');
-- DDL and sample data population, end

DECLARE @PI_ID VARCHAR(20) = '9983950';

SELECT ID
    , xmldata.value('(/PROJECTS/row/ORG_CITY/text())[1]', 'VARCHAR(30)') as ORG_CITY
FROM @tbl 
WHERE xmldata.exist('/PROJECTS/row/PIS/PI/PI_ID[contains(./text()[1], sql:variable("@PI_ID"))]') = 1;