SQL Server XML添加不同类型的多个节点

时间:2019-01-24 22:47:00

标签: sql-server xml

我正在寻求以这种格式创建输出xml,但是我无法在Child下添加节点Feature and Categories。我可以一次添加一个,但不能两个都添加。

<Parent>
    <Child>
        <Features>
            <Feature Id="f1" />
            <Feature Id="f2" />
            <Feature Id="f3" />
        </Features>
        <Categories>
            <Category Name="c1">
                <Feature>f1</Feature>
                <Feature>f2</Feature>
            </Category>
            <Category Name="c2">
                <Feature>f2</Feature>
                <Feature>f3</Feature>
            </Category>
            <Category Name="c3">
                <Feature>f2</Feature>
            </Category>
    </Child>
</Parent>

这是我的SQL,用于使用<Features>节点和<Category>节点创建两个XML字符串:

DECLARE @CategoryFeatures TABLE (CategoryId VARCHAR(5), FeatureId VARCHAR(5))

INSERT INTO @CategoryFeatures VALUES ('c1', 'f1')
INSERT INTO @CategoryFeatures VALUES ('c1', 'f2')
INSERT INTO @CategoryFeatures VALUES ('c2', 'f2')
INSERT INTO @CategoryFeatures VALUES ('c2', 'f3')
INSERT INTO @CategoryFeatures VALUES ('c3', 'f2')

SELECT 
(
    SELECT
    (
        SELECT [@Id] = FeatureId
        FROM CategoryFeatures
        GROUP BY FeatureId
        FOR XML PATH ('Feature'), ROOT ('Features'), TYPE)
    FOR XML PATH ('Child'), TYPE)
FOR XML PATH ('Parent')


SELECT 
(
    SELECT
    (
        SELECT [@Name] = cat.CategoryId,
        (
            SELECT Feature = cf.FeatureId
            FROM CategoryFeatures cf
            WHERE cf.CategoryId = cat.CategoryId
            FOR XML PATH (''), TYPE)
        FROM CategoryFeatures cat
        GROUP BY cat.CategoryId
        FOR XML PATH ('Category'), ROOT ('Categories'), TYPE)
    FOR XML PATH ('Child'), TYPE)
FOR XML PATH ('Parent')

如何使这两个节点处于同一级别,以使其看起来像上面的预期输出?谢谢。

2 个答案:

答案 0 :(得分:1)

一种可能性是狂欢的子查询。

SELECT (SELECT (SELECT cf1.featureid "Feature/@Id"
                       FROM (SELECT DISTINCT
                                    cf0.featureid
                                    FROM @categoryfeatures cf0) cf1
                       FOR XML PATH(''),
                               TYPE)
               FOR XML PATH('Features'),
                       TYPE),
       (SELECT (SELECT cf1.categoryid "Category/@Name",
                       (SELECT cf2.featureid "Feature"
                               FROM @categoryfeatures cf2
                               WHERE cf2.categoryid = cf1.categoryid
                               FOR XML PATH(''),
                                       TYPE) "Category"
                       FROM (SELECT DISTINCT
                                    cf0.categoryid
                                    FROM @categoryfeatures cf0) cf1
                       FOR XML PATH(''),
                               TYPE)
               FOR XML PATH('Categories'),
                       TYPE)
       FOR XML PATH('Child'),
               ROOT('Parent');

db<>fiddle

答案 1 :(得分:1)

btw:我喜欢粘性位的表达方式狂欢的子查询;-)

这将需要子查询,但可以简化一些:

DECLARE @CategoryFeatures TABLE (CategoryId VARCHAR(5), FeatureId VARCHAR(5))

INSERT INTO @CategoryFeatures VALUES 
 ('c1', 'f1')
,('c1', 'f2')
,('c2', 'f2')
,('c2', 'f3')
,('c3', 'f2');

-查询将使用一些AS [Path/Path2/@Attr]来避免嵌套查询...

SELECT 
( 
    SELECT cf.FeatureId AS [Feature/@Id]
    FROM @CategoryFeatures cf
    GROUP BY cf.FeatureId
    FOR XML PATH(''),TYPE
) AS [Child/Features]
,
(
    SELECT cf.CategoryId AS [Category/@Name]
          ,(
            SELECT cf2.FeatureId AS [*]
            FROM @CategoryFeatures cf2
            WHERE cf2.CategoryId=cf.CategoryId
            FOR XML PATH('Feature'),TYPE
           ) AS [Category]
    FROM @CategoryFeatures cf
    GROUP BY cf.CategoryId
    FOR XML PATH(''),TYPE
) AS [Child/Categories]
FOR XML PATH(''),ROOT('Parent');

结果:

<Parent>
  <Child>
    <Features>
      <Feature Id="f1" />
      <Feature Id="f2" />
      <Feature Id="f3" />
    </Features>
    <Categories>
      <Category Name="c1">
        <Feature>f1</Feature>
        <Feature>f2</Feature>
      </Category>
      <Category Name="c2">
        <Feature>f2</Feature>
        <Feature>f3</Feature>
      </Category>
      <Category Name="c3">
        <Feature>f2</Feature>
      </Category>
    </Categories>
  </Child>
</Parent>

更新您可以使用FLWOR进行同样的操作

尝试一下

SELECT
(SELECT * FROM @CategoryFeatures FOR XML PATH('row'),ROOT('Parent'),TYPE)
.query
('
    <Parent>
    <Child>
    {
        <Features>
        {
            for $f in distinct-values(/Parent/row/FeatureId)
            return <Feature Id="{$f}" />
        }
        </Features>
    }
    {
        <Categories>
        {
            for $c in distinct-values(/Parent/row/CategoryId)
            return <Category Name="{$c}">
                   {
                    for $f in distinct-values(/Parent/row[CategoryId=$c]/FeatureId)
                    return <FeatureId>{$f}</FeatureId>
                   }
                   </Category>          
        }
        </Categories>
    }
    </Child>
    </Parent>
');