根据XML属性值获取SQL记录

时间:2016-10-24 18:15:36

标签: sql-server xml tsql xpath xquery

我已经使用T-SQL完成了一些基本的XML查询,但我不确定如何解决这个问题。

我想查询表中特定XML属性具有请求值的所有行。

这是我的表架构:

CREATE TABLE [dbo].[Applications_Submissions]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [SubmissionGuid] [uniqueidentifier] NOT NULL,
    [TestMode] [bit] NOT NULL,
    [SubmissionID] [int] NOT NULL,
    [Status] [int] NOT NULL,
    [ProcessId] [int] NOT NULL,
    [Version] [int] NOT NULL,
    [ReturnUrl] [nvarchar](1000) NULL,
    [Applications] [xml] NOT NULL,
    [CreatedByUser] [int] NOT NULL,
    [DateCreated] [datetime] NOT NULL,
    [DateDeleted] [datetime] NULL,

    PRIMARY KEY CLUSTERED ([Id] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [FG_Applications]
) ON [FG_Applications] TEXTIMAGE_ON [FG_Applications]

[Application]列中存储的XML数据结构如下:

<Submission xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="15" TestMode="false" SubmissionId="15" Status="0" ProcessId="0" Version="1" CreatedByUser="2" DateCreated="2016-09-28T15:08:25.667" DateDeleted="0001-01-01T00:00:00">
  <ReturnUrl>/Register/RegistrationData/Register/1094/1/[SGUID]</ReturnUrl>
  <SubmissionGuid>f1891c84-1fda-41b4-a78b-605bfdcaf45a</SubmissionGuid>
  <Applications>
    <Application ApplicationID="15" ApplicationName="Test Form">
      <FriendlyUrl>test-form-1234</FriendlyUrl>
      <Pages>
        <Page PageId="16" ApplicationId="15" ViewOrder="0">
          <PageTitle>Page 1</PageTitle>
          <Fields>
            <Field FieldId="26" FieldType="10" ViewOrder="0">
              <FieldTitle>Who are you</FieldTitle>
              <FieldValues>Jeffrey</FieldValues>
              <FieldsResponses />
              <PossibleFieldValues />
            </Field>
            <Field FieldId="27" FieldType="0" ViewOrder="0">
              <FieldTitle>Why are you here?</FieldTitle>
              <FieldValues />
              <FieldsResponses />
              <PossibleFieldValues />
            </Field>
            <Field FieldId="28" FieldType="5" ViewOrder="0">
              <FieldTitle>Pick any</FieldTitle>
              <FieldsResponses>
                <FieldsResponse FieldResponseId="19" LinkToApplication="0" ViewOrder="0" Selected="false">
                  <Response>One</Response>
                </FieldsResponse>
                <FieldsResponse FieldResponseId="20" LinkToApplication="12" ViewOrder="0" Selected="false">
                  <Response>Two</Response>
                </FieldsResponse>
                <FieldsResponse FieldResponseId="21" LinkToApplication="0" ViewOrder="0" Selected="false">
                  <Response>Three</Response>
                </FieldsResponse>
              </FieldsResponses>
              <PossibleFieldValues />
            </Field>
          </Fields>
        </Page>
        <Page PageId="17" ApplicationId="15" ViewOrder="0">
          <PageTitle>Page 2</PageTitle>
          <Fields>
            <Field FieldId="29" FieldType="6" ViewOrder="0">
              <FieldTitle>Agreement</FieldTitle>
              <FieldsResponses>
                <FieldsResponse FieldResponseId="22" LinkToApplication="16" ViewOrder="0" Selected="false">
                  <Response>I agree</Response>
                </FieldsResponse>
                <FieldsResponse FieldResponseId="23" LinkToApplication="16" ViewOrder="0" Selected="false">
                  <Response>I disagree</Response>
                </FieldsResponse>
              </FieldsResponses>
              <PossibleFieldValues />
            </Field>
          </Fields>
        </Page>
      </Pages>
    </Application>
  </Applications>
</Submission>

我想根据存储在ApplicationID节点中的<Application>属性获取表行。每个<Submission>可以有多个<Application>个节点。

这样做的最佳方式是什么?

非常感谢你!

1 个答案:

答案 0 :(得分:1)

最好的是xml.exist()。但是这将从不快速...如果你需要更频繁或更多的行数,你应该将ApplicationID与实际的rowID一起提取到一个辅助表中。这可以在触发器中完成。

但你可以试试这个:

- 模拟表

DECLARE @Applications_Submissions TABLE(Id INT IDENTITY NOT NULL,TestText VARCHAR(MAX),Applications XML);

- 插入两个模拟行

INSERT INTO @Applications_Submissions VALUES
('Contains ApplicationID 15, 16 and 100'
 ,N'<Submission xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="15" TestMode="false" SubmissionId="15" Status="0" ProcessId="0" Version="1" CreatedByUser="2" DateCreated="2016-09-28T15:08:25.667" DateDeleted="0001-01-01T00:00:00">
  <Applications>
    <Application ApplicationID="15" ApplicationName="Test Form">
      <FriendlyUrl>blah 15</FriendlyUrl>
    </Application>
    <Application ApplicationID="16" ApplicationName="Test Form">
      <FriendlyUrl>blah 16</FriendlyUrl>
    </Application>
    <Application ApplicationID="100" ApplicationName="Test Form">
      <FriendlyUrl>blah 100</FriendlyUrl>
    </Application>
  </Applications>
</Submission>')
,('Contains ApplicationID 15, 17 and 200'
  ,N'<Submission xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="15" TestMode="false" SubmissionId="15" Status="0" ProcessId="0" Version="1" CreatedByUser="2" DateCreated="2016-09-28T15:08:25.667" DateDeleted="0001-01-01T00:00:00">
  <Applications>
    <Application ApplicationID="15" ApplicationName="Test Form">
      <FriendlyUrl>blah 15</FriendlyUrl>
    </Application>
    <Application ApplicationID="17" ApplicationName="Test Form">
      <FriendlyUrl>blah 17</FriendlyUrl>
    </Application>
    <Application ApplicationID="200" ApplicationName="Test Form">
      <FriendlyUrl>blah 200</FriendlyUrl>
    </Application>
  </Applications>
</Submission>');

- 这就是你要搜索的内容

--Try different values (15 returns both rows, 16, 100 or 200 just one row and any other value none
DECLARE @ApplicationID INT=15; 

- 这是查询

- Btw:我使用wildcard-namespace来避免与你的实际命名空间混淆......

SELECT Id
      ,TestText

      --This is just to show, how you would fetch a value from the given ApplicationID
      ,Applications.value('(/*:Submission/*:Applications/*:Application[(@*:ApplicationID)[1] eq sql:variable("@ApplicationID")]/*:FriendlyUrl)[1]','nvarchar(max)')

FROM @Applications_Submissions
WHERE Applications.exist('/*:Submission/*:Applications/*:Application[(@*:ApplicationID)[1] eq sql:variable("@ApplicationID")]')=1