使用 xml 元素 (Tsql) 查询(很多)XML 特定文本的数据

Querying (a lot of) XML data for specific text with in xml Elements (Tsql)

抱歉:post 有点长(想确保所有相关内容都在)

努力让我的大脑围绕这个一点点。 我有一个 table 有 5 列

ID (varchar)
Record value(XML)
date (datetime)
applicationtypeid (int)
applicationstatusid(int)

XML 包含大量数据,但我感兴趣的部分看起来像这样。

<GoodsAndServicesItemSummaryViewModelItems>
  <GoodsAndServicesMasterViewModel>
    <Id>1</Id>
    <ClassId>1</ClassId>
    <TermsText>text</TermsText>
    <TermsCreationType>ManuallyEntered</TermsCreationType>
    <Terms />

特别是 "TermsCreationType" 元素。其中可以是以下3个字符串之一:

根据客户文件的不同,也可能是所有这三种的混合,并且它们可以包含理论上想要的尽可能多的这些混合物,即:

 </PriorityClaimAdditionalDetailWizardStepViewModel>
  <GoodsAndServicesMasterViewModel>
    <Id>9</Id>
    <ClassId>2</ClassId>
    <TermsText>texty</TermsText>
    <TermsCreationType>ManuallyEntered</TermsCreationType>
    <Terms />
  </GoodsAndServicesMasterViewModel>
  <GoodsAndServicesMasterViewModel>
    <Id>10</Id>
    <ClassId>1</ClassId>
    <TermsText>text</TermsText>
    <TermsCreationType>ManuallyEntered</TermsCreationType>
    <Terms />
  </GoodsAndServicesMasterViewModel>
</GoodsAndServicesItemSummaryViewModelItems>
<GoodsAndServicesItemSummaryViewModelItemsUnMerged>
  <GoodsAndServicesMasterViewModel>
    <Id>9</Id>
    <ClassId>9</ClassId>
    <TermsText>test</TermsText>
    <TermsCreationType>CopyFromExistingMarks</TermsCreationType>
    <Terms />
  </GoodsAndServicesMasterViewModel>

我正在尝试计算某个日期范围内有多少条记录

  1. 仅包含上述之一(无论它出现一次还是出现 50 次,只要它是该元素中的唯一值)

  2. 包含三者任意混合的记录。


到目前为止,我对 "one element only" 的尝试是:

SELECT Count (id) [pre-approved only]
FROM   [TMWebForms].[dbo].[webformapplication]
WHERE  trademarkid NOT IN (SELECT id
                           FROM   [TMWebForms].[dbo].[webformapplication]
                           WHERE  applicationtypeid = '5'
                                  AND createddate BETWEEN '2016-08-01' AND '2016-08-31'
                                  AND RECORDDATA.value('contains((//GoodsAndServicesWizardStepViewModel/GoodsAndServicesItemSummaryViewModelItems/GoodsAndServicesMasterViewModel/TermsCreationType/text())[1], "ManuallyEntered")', 'bit') = 1
                                  AND applicationstatusid = 50
                                  AND applicationtypeid = 5)
       AND id NOT IN (SELECT id
                      FROM   [TMWebForms].[dbo].[webformapplication]
                      WHERE  applicationtypeid = '5'
                             AND createddate BETWEEN '2016-08-01' AND '2016-08-31'
                             AND RECORDDATA.value('contains((//GoodsAndServicesWizardStepViewModel/GoodsAndServicesItemSummaryViewModelItems/GoodsAndServicesMasterViewModel/TermsCreationType/text())[1], "CopyFromExistingMark")', 'bit') = 1
                             AND applicationstatusid = 50
                             AND applicationtypeid = 5)
       AND createddate BETWEEN '2016-08-01' AND '2016-08-31'
       AND RECORDDATA.value('contains((//GoodsAndServicesWizardStepViewModel/GoodsAndServicesItemSummaryViewModelItems/GoodsAndServicesMasterViewModel/TermsCreationType/text())[1], "CopyFromPreapprovedTermsDatabase")', 'bit') = 1
       AND applicationstatusid = 50
       AND applicationtypeid = 5 
  1. 这是长篇大论,从长远来看并不是最好的表现! (我考虑过将其转换为字符串然后使用 "like" - 但这可能同样糟糕,甚至更糟)

  2. 它并没有完全拉回我想要的。对我来说,它只搜索 "CopyFromPreapprovedTermsDatabase",但在查询数据时,在少数情况下这是第一行,但我也可以看到 "manuallyentered" 存在。

在此感谢任何帮助!

像这样尝试

(我不得不添加一个 root 并添加一些开始和结束标签)

DECLARE @xml XML=
N'<SomeRoot>
  <GoodsAndServicesItemSummaryViewModelItems>
    <GoodsAndServicesMasterViewModel>
      <Id>9</Id>
      <ClassId>2</ClassId>
      <TermsText>texty</TermsText>
      <TermsCreationType>ManuallyEntered</TermsCreationType>
      <Terms />
    </GoodsAndServicesMasterViewModel>
    <GoodsAndServicesMasterViewModel>
      <Id>10</Id>
      <ClassId>1</ClassId>
      <TermsText>text</TermsText>
      <TermsCreationType>ManuallyEntered</TermsCreationType>
      <Terms />
    </GoodsAndServicesMasterViewModel>
  </GoodsAndServicesItemSummaryViewModelItems>
  <GoodsAndServicesItemSummaryViewModelItemsUnMerged>
    <GoodsAndServicesMasterViewModel>
      <Id>9</Id>
      <ClassId>9</ClassId>
      <TermsText>test</TermsText>
      <TermsCreationType>CopyFromExistingMarks</TermsCreationType>
      <Terms />
    </GoodsAndServicesMasterViewModel>
  </GoodsAndServicesItemSummaryViewModelItemsUnMerged>
</SomeRoot>';

DECLARE @tbl TABLE(ID VARCHAR(10),Record_Value XML,[date] DATETIME,applicationtypeid INT,applicationstautsid INT);
INSERT INTO @tbl VALUES('SomeTest',@xml,GETDATE(),11,22);

--CTE 将 select 所有列并添加具有给定 text()

的 TermsCreationType 的实际计数
WITH CTE AS
(
    SELECT *
          ,Record_Value.value('count(//TermsCreationType[text()="ManuallyEntered"])','int') AS CountManuallyEntered
          ,Record_Value.value('count(//TermsCreationType[text()="CopyFromExistingMarks"])','int') AS CountCopyFromExistingMarks
          ,Record_Value.value('count(//TermsCreationType[text()="CopyFromPreapprovedTermsDatabase"])','int') AS CountCopyFromPreapprovedTermsDatabase
    FROM @tbl
)

--最终的SELECT使用大的CASE WHEN层次结构来分析计数

SELECT *
      ,CASE WHEN CTE.CountManuallyEntered=0 AND CTE.CountCopyFromExistingMarks=0 AND CTE.CountCopyFromPreapprovedTermsDatabase=0 THEN 'None' 
       ELSE
           CASE WHEN CTE.CountManuallyEntered>0 AND CTE.CountCopyFromExistingMarks=0 AND CTE.CountCopyFromPreapprovedTermsDatabase=0 THEN 'Manually' 
           ELSE
               CASE WHEN CTE.CountManuallyEntered=0 AND CTE.CountCopyFromExistingMarks>0 AND CTE.CountCopyFromPreapprovedTermsDatabase=0 THEN 'Existing' 
               ELSE
                   CASE WHEN CTE.CountManuallyEntered=0 AND CTE.CountCopyFromExistingMarks=0 AND CTE.CountCopyFromPreapprovedTermsDatabase>0 THEN 'Preapproved' 
                   ELSE
                   'Mixed'
                   END
               END
           END
       END AS CountAnalysis
FROM CTE;