【问题标题】:SQL Server Recursion - Query Assistance to calculate current & overall totalsSQL Server 递归 - 查询帮助以计算当前和总体总计
【发布时间】:2021-10-02 13:53:09
【问题描述】:

我有一个递归场景,我正在尝试解决,但无法使用 TSQL 解决,我正在寻求专业知识和帮助。

场景: 我正在处理课程课程和参加这些课程的学生人数。 每年都有一定数量的学生报名参加第一期课程,或者毕业到下一期课程。

会话如下所示:

每个会话都知道下一个会话的 ID。 例如学生从 2015 年第 1 学期开始,并在 2016 年进入第 2 学期。 最后一个会话没有 nextSessionID。

最终目标是通过两个聚合来按顺序获取会话:

  1. 第一个会话中加入的总数。
  2. 当前会话的总数。 (注意 - 此处列出的总数是任意值,与下面的示例数据不匹配)

我尝试过的: 我已经弄清楚如何获取 nextSessionID。 然后我尝试将其放入递归 CTE 中。但是,我无法让它超过 1 级。

我会很感激一些关于采取这个方向的指示。 下面列出了创建示例表和数据的代码。

感谢任何帮助和专业知识。

--create session table
create table #sessions
(
sessionInstanceID int,
SessionYear int,
AcademicYear int,
NextSessionInstanceID int
)


--populate session table
insert into #sessions(sessionInstanceID,SessionYear, AcademicYear, NextSessionInstanceID)
values( 1001    ,   1   ,   2015    ,   1006),
(   1002    ,   2   ,   2015    ,   1007),
(   1003    ,   3   ,   2015    ,   1008),
(   1004    ,   4   ,   2015    ,   null),
(   1005    ,   1   ,   2016    ,   1009),
(   1006    ,   2   ,   2016    ,   1010),
(   1007    ,   3   ,   2016    ,   1011),
(   1008    ,   4   ,   2016    ,   1012),
(   1009    ,   1   ,   2017    ,   null),
(   1010    ,   2   ,   2017    ,   null),
(   1011    ,   3   ,   2017    ,   null),
(   1012    ,   4   ,   2017    ,   null)


--create enrolment table 
create table #enroledStudents
(
     
    sessionInstanceID int,
    studentID int
)


--populate enrolment table 
insert into #enroledStudents
values(1001, 1)
,(1001, 2)
,(1001, 3)
,(1001, 4)
,(1001, 5)
,(1001, 6)
,(1002, 1)
,(1002, 3)
,(1002, 4)
,(1002, 5)
,(1002, 6)
,(1003, 1)
,(1003, 3)
,(1003, 4)
,(1004, 1)
,(1005, 10)
,(1005, 11)
,(1005, 12)
,(1005, 13)
,(1006, 11)
,(1006, 12)
,(1006, 13)
,(1007, 11)
,(1007, 12)
,(1007, 13)
,(1008, 24)
,(1008, 25)
,(1008, 26)

    
    --get sessions & the next academicSessionID
    select s.sessionInstanceID as currentInstanceID, s.SessionYear as currentSessionYear, s.AcademicYear as currentAcademicYear,
    s2.sessionInstanceID as nextSessionInstanceID , s2.SessionYear as nextSessionYear, s2.AcademicYear as nextAcademicYear
    from #sessions s
    left join #sessions s2 on s.AcademicYear = s2.AcademicYear - 1
    and s.SessionYear = s2.SessionYear -1

with cte as
(
    select * from #sessionsHierarchy
    union all
    
    select #sessionsHierarchy.* 
    from cte 
    join #sessionsHierarchy on cte.nextSessionInstanceID = #sessionsHierarchy.currentInstanceID

    
)
select cte.currentInstanceID, cte.currentAcademicYear, cte.currentAcademicYear,
--count()
from cte
join #enroledStudents on cte.currentInstanceID = #enroledStudents.sessionInstanceID

【问题讨论】:

    标签: sql-server tsql common-table-expression


    【解决方案1】:

    目前尚不完全清楚您想要什么结果,但这将为您提供以sessionInstanceID 开头的所有结果,然后按链中的顺序排列。

    我们还计算课程的学生总数

    WITH cte AS
    (
        SELECT
          sessionInstanceID,
          NextSessionInstanceID,
          AcademicYear,
          startingId = sessionInstanceID,
          lvl = 1
        FROM sessions s
        WHERE NOT EXISTS (SELECT 1
          FROM sessions s2
          WHERE s2.NextSessionInstanceID = s.sessionInstanceID)
    
        UNION ALL
        
        SELECT
          s.sessionInstanceID,
          s.NextSessionInstanceID,
          s.AcademicYear,
          cte.startingId,
          cte.lvl + 1
        FROM cte 
        JOIN sessions s on s.sessionInstanceID = cte.nextSessionInstanceID
    )
    SELECT
      sessionInstanceID,
      AcademicYear,
      StartingTotalStudents = (
            SELECT TotalStudents = COUNT(*)
            FROM enroledStudents e
            WHERE e.sessionInstanceID = cte.startingId
        ),
      TotalStudents = (
            SELECT TotalStudents = COUNT(*)
            FROM enroledStudents e
            WHERE e.sessionInstanceID = cte.sessionInstanceID
        )
    FROM cte
    ORDER BY startingId, lvl;
    

    db<>fiddle.uk

    【讨论】:

    • 谢谢,这很有帮助。对缺乏明确性表示歉意。为简化起见,我认为主要目标是能够按照学生学习进度的顺序安排课程。即学生从 2015 学年第 1 学年开始,进入 2016 学年第 2 学年,然后是 2017 学年第 3 学年,依此类推。无法像这样对会话进行排序,也无法通过分组列轻松选择这些会话。
    【解决方案2】:

    更新:

    经过相当多的数据探索后,很明显,以基于集合的方式很难做到这一点。

    我将问题定义为需要为所有课程添加入学年份。 这个标准有点复杂,所以最简单的解决方案是一点 python 和几个循环!不像我喜欢的那样优雅,但结果符合要求且功能强大。

    感谢您的建议和帮助。

    【讨论】:

      猜你喜欢
      • 2015-07-09
      • 1970-01-01
      • 2021-05-06
      • 2017-01-19
      • 1970-01-01
      • 2011-07-19
      • 2013-11-26
      • 2015-02-22
      • 1970-01-01
      相关资源
      最近更新 更多