【问题标题】:Group XML output based on a hardcoded number using SQL使用 SQL 根据硬编码数字对 XML 输出进行分组
【发布时间】:2020-09-20 16:37:34
【问题描述】:

我有一个以 XML 形式提供输出的查询。

DECLARE @XMLDATA1 XML 
SET @XMLDATA1 = (


SELECT StudentId AS 'StudentID',
StudentName AS 'StudentName',
StudentAge AS 'Age',
StudentYear 'Year'

FROM Student 
ORDER BY StudentId
FOR XML PATH('StudentLine')
)

SELECT ( CAST(@XMLDATA1 AS XML ))
FOR XML PATH ('StudentRecords') , Root('Student')

示例输出如下。

<StudentRecords>
    <Student>
        <StudentLine>
            <StudentID>12</StudentID>
            <StudentName>Kevin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
        <StudentLine>
            <StudentID>13</StudentID>
            <StudentName>Peter</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
        <StudentLine>
            <StudentID>14</StudentID>
            <StudentName>Martin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
        <StudentLine>
            <StudentID>15</StudentID>
            <StudentName>Justin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
    </Student>
</StudentRecords>

我想根据 sql 查询中的硬编码数字将这些记录从 &lt;StudentRecords&gt; 标记中拆分出来。例如,如果我想拆分为 3 条记录,则 xml 将如下所示。

<StudentRecords>
    <Student>
        <StudentLine>
            <StudentID>12</StudentID>
            <StudentName>Kevin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
        <StudentLine>
            <StudentID>13</StudentID>
            <StudentName>Peter</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
        <StudentLine>
            <StudentID>14</StudentID>
            <StudentName>Martin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
    </Student>
</StudentRecords>
<StudentRecords>
    <Student>
        <StudentLine>
            <StudentID>15</StudentID>
            <StudentName>Justin</StudentName>
            <Age>10</Age>
            <Year>5</Year>
        </StudentLine>
    </Student>
</StudentRecords>

可能有这样的场景,比如有 100000 个&lt;StudentLine&gt; 标签的记录,硬编码的数字可以是 2000。 有人可以帮助我实现这一目标。 谢谢。

【问题讨论】:

    标签: sql-server xml tsql grouping xquery


    【解决方案1】:

    这里是如何通过 XQuery 和 FLWOR 表达式来实现它。

    • 组中的行数将作为输入参数。
    • 我们将使用NTILE()函数根据数量创建组 组中的行数。
    • FLWOR 表达式有两个循环:(1) 遍历组,(2) 遍历给定组中的 &lt;StudentLine&gt; 元素。

    SQL

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (StudentID INT PRIMARY KEY, StudentName VARCHAR(30), Age INT);
    INSERT INTO @tbl (StudentID, StudentName, Age) VALUES
    (1,  'Martha',  10),
    (2,  'Boris',  12),
    (3,  'Judy',  15),
    (12, 'Kevin',  19),
    (13, 'Peter',  10),
    (14, 'Martin', 18),
    (15, 'Justin', 25);
    -- DDL and sample data population, end
    
    -- denominator specifies # of rows in a group
    DECLARE @NumOfGroups DECIMAL(10,1) = (SELECT COUNT(*) FROM @tbl) / 3.0;
    SET @NumOfGroups = CEILING(@NumOfGroups);
    
    -- just to see
    SELECT groupId = NTILE(CAST(@NumOfGroups AS INT)) OVER (ORDER BY StudentID)
        , *
    FROM @tbl;
    
    SELECT (
        SELECT groupID = NTILE (CAST(@NumOfGroups AS INT)) OVER (ORDER BY StudentID)
            , *
        FROM @tbl
        FOR XML PATH('StudentLine'), TYPE, ROOT('root')
    ).query('
    
        for $gr in distinct-values(/root/StudentLine/groupID/text())
        return <StudentRecords>
                    <Student>
                {
                    for $x in /root/StudentLine[(groupID/text())[1] eq $gr]
                    return $x
                }
            </Student>
        </StudentRecords>
    
    ');
    

    输出

      <StudentRecords>
        <Student>
          <StudentLine>
            <groupID>1</groupID>
            <StudentID>1</StudentID>
            <StudentName>Martha</StudentName>
            <Age>10</Age>
          </StudentLine>
          <StudentLine>
            <groupID>1</groupID>
            <StudentID>2</StudentID>
            <StudentName>Boris</StudentName>
            <Age>12</Age>
          </StudentLine>
          <StudentLine>
            <groupID>1</groupID>
            <StudentID>3</StudentID>
            <StudentName>Judy</StudentName>
            <Age>15</Age>
          </StudentLine>
        </Student>
      </StudentRecords>
      <StudentRecords>
        <Student>
          <StudentLine>
            <groupID>2</groupID>
            <StudentID>12</StudentID>
            <StudentName>Kevin</StudentName>
            <Age>19</Age>
          </StudentLine>
          <StudentLine>
            <groupID>2</groupID>
            <StudentID>13</StudentID>
            <StudentName>Peter</StudentName>
            <Age>10</Age>
          </StudentLine>
        </Student>
      </StudentRecords>
      <StudentRecords>
        <Student>
          <StudentLine>
            <groupID>3</groupID>
            <StudentID>14</StudentID>
            <StudentName>Martin</StudentName>
            <Age>18</Age>
          </StudentLine>
          <StudentLine>
            <groupID>3</groupID>
            <StudentID>15</StudentID>
            <StudentName>Justin</StudentName>
            <Age>25</Age>
          </StudentLine>
        </Student>
      </StudentRecords>
    

    【讨论】:

    • 嗨@Yitzhak Khabinsky 感谢您的回答,但xml 的根目录中不应有 标记。没有共同的根标签。分组明智,这个标签应该是每个组的公共根标签 。
    • @RasangaAbeykoon,我的回答是生成格式良好的 XML。如果您不需要格式正确的 XML,只需删除根标记即可。
    • @RasangaAbeykoon,我更新了答案。不再有根元素。它使输出 XML 成为一个片段。
    【解决方案2】:

    这对我有效,无需 FLWOR

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (StudentID INT PRIMARY KEY, StudentName VARCHAR(30), Age INT);
    INSERT INTO @tbl (StudentID, StudentName, Age) VALUES
    (1,  'Martha',  10),
    (2,  'Boris',  12),
    (3,  'Judy',  15),
    (12, 'Kevin',  19),
    (13, 'Peter',  10),
    (14, 'Martin', 18),
    (15, 'Justin', 25);
    -- DDL and sample data population, end
    
    -- denominator specifies # of rows in a group
    DECLARE @NumOfGroups DECIMAL(10,1) = (SELECT COUNT(*) FROM @tbl) / 3.0;
    SET @NumOfGroups = CEILING(@NumOfGroups);
    
    -- no FLWOR used
    WITH c AS   (
                SELECT groupID = NTILE (CAST(@NumOfGroups AS INT)) OVER (ORDER BY StudentID)
                    , *
                FROM @tbl
                )
    SELECT      (   SELECT      StudentID, StudentName, Age
                    FROM        c
                    WHERE       c.groupID = g.groupID
                    FOR XML     PATH('StudentLine'), TYPE   ) AS Student
    FROM        (
                SELECT DISTINCT groupID FROM c
                ) g
    FOR XML     PATH('')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-01
      • 2022-01-19
      • 2017-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多