Как объединить значения элементов в XQuery для SQL Server? - PullRequest
0 голосов
/ 04 июня 2019

Если у меня есть этот XML

<TradingInquirySearchResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SearchTerm>test</SearchTerm>
  <CompanyFound>true</CompanyFound>
  <CompanyInfoCollection>
    <CompanyInfo>
      <CompanyID>26</CompanyID>
      <CompanyName>test</CompanyName>
      <Status>Unrestricted</Status>
      <SearchTags>
        <Tag>test2</Tag>
        <Tag>test3</Tag>
        <Tag>test4</Tag>
      </SearchTags>
    </CompanyInfo>
  </CompanyInfoCollection>
</TradingInquirySearchResult>

Я хочу получить "test2;test3;test4". Как я могу объединить значения <Tag> для первого тега <CompanyInfo>?

Я пытался TransactionData.value('(/TradingInquirySearchResult/CompanyInfoCollection/CompanyInfo[1]/SearchTags/Tag)[1]', 'nvarchar(1000)')

но это не сработало.

Спасибо

1 Ответ

1 голос
/ 04 июня 2019

Поскольку вы используете SQL Server 2012 (точнее, не 2017+), общий способ агрегирования строк - это использование FOR XML PATH и STUFF, и вы можете получить несколько значений для узла Tag, используя nodes оператор. Это дает вам следующее:

DECLARE @XML xml = '
<TradingInquirySearchResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SearchTerm>test</SearchTerm>
  <CompanyFound>true</CompanyFound>
  <CompanyInfoCollection>
    <CompanyInfo>
      <CompanyID>26</CompanyID>
      <CompanyName>test</CompanyName>
      <Status>Unrestricted</Status>
      <SearchTags>
        <Tag>test2</Tag>
        <Tag>test3</Tag>
        <Tag>test4</Tag>
      </SearchTags>
    </CompanyInfo>
  </CompanyInfoCollection>
</TradingInquirySearchResult>';


SELECT STUFF((SELECT N';' +  ST.Tag.value('(./text())[1]','nvarchar(100)')
              FROM (VALUES(@XML))V(X)
              CROSS APPLY V.X.nodes('/TradingInquirySearchResult/CompanyInfoCollection/CompanyInfo/SearchTags/Tag') ST(Tag)
              FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') AS Tags

Изменить для догадки, когда несколько компаний.

Если вы хотите только первую компанию, тогда да, использование [1] будет работать:

DECLARE @XML xml = '
<TradingInquirySearchResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SearchTerm>test</SearchTerm>
  <CompanyFound>true</CompanyFound>
  <CompanyInfoCollection>
    <CompanyInfo>
      <CompanyID>26</CompanyID>
      <CompanyName>test</CompanyName>
      <Status>Unrestricted</Status>
      <SearchTags>
        <Tag>test2</Tag>
        <Tag>test3</Tag>
        <Tag>test4</Tag>
      </SearchTags>
    </CompanyInfo>
    <CompanyInfo>
      <CompanyID>27</CompanyID>
      <CompanyName>Sample</CompanyName>
      <Status>Restricted</Status>
      <SearchTags>
        <Tag>test6</Tag>
        <Tag>test7</Tag>
        <Tag>test8</Tag>
      </SearchTags>
    </CompanyInfo>
  </CompanyInfoCollection>
</TradingInquirySearchResult>';


SELECT STUFF((SELECT N';' +  ST.Tag.value('(./text())[1]','nvarchar(100)')
              FROM (VALUES(@XML))V(X)
              CROSS APPLY V.X.nodes('/TradingInquirySearchResult/CompanyInfoCollection/CompanyInfo[1]/SearchTags/Tag') ST(Tag)
              FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') AS Tags;

Если, однако, вам нужна строка для каждой компании, то вы хотели бы сделать что-то вроде этого:

SELECT CIC.CI.value('(./CompanyID/text())[1]','nvarchar(50)') AS CompanyID,
       STUFF((SELECT N';' +  ST.Tag.value('(./text())[1]','nvarchar(100)')
              FROM CIC.CI.nodes('./SearchTags/Tag') ST(Tag)
              FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') AS Tags
FROM (VALUES(@XML))V(X)
CROSS APPLY V.X.nodes('/TradingInquirySearchResult/CompanyInfoCollection/CompanyInfo') CIC(CI);
...