如何使用另一张表的参数循环遍历一张表

huangapple go评论63阅读模式
英文:

How loop one table with parameter from another table

问题

我有下面的两张表:
表格“grade”用于为学生分配成绩,分配数量为0表示剩下的学生记录。

tblGrade
排名     成绩     分配数量     备注
1      A      3     
2     B+     5     
3      B     5     
4      C     5     
5      D     0     剩余

还有一个名为“tblStudentGrade”的表,包含两列“StudentID”和“Score”。我需要使用来自“tblGrade”的参数查询这个表,以获取以下结果。

tblStudentGrade
学生ID     分数     成绩
S0001     100     A
S0002     99     A
S0014     99     A
S0008     98     B+
S0013     90     B+
S0007     78     B+
S0024     75     B+
S0022     68     B+
S0018     66     B
S0004     59     B
S0006     56     B
S0011     56     B
S0012     56     B
S0017     55     C
S0009     54     C
S0003     50     C
S0023     45     C
S0016     34     C
S0021     26     D
S0005     23     D
S0010     23     D
S0019     23     D
S0020     18     D
S0015     12     D

非常感谢您的帮助。

英文:

I have 2 tables below:
table grade is to set the grade to student with allocate qty, zero value means the rest record of students.

tblGrade	
Rank	Grade	Allocate Qty	Remark
1	A	3	
2	B+	5	
3	B	5	
4	C	5	
5	D	0	The rest

and tblStudentGrade with 2 coluomns StudentID and Score. I need to query this table with parameter from tblGrade to get below result.

tblStudentGrade		
StudentID	Score	Grade
S0001	100	A
S0002	99	A
S0014	99	A
S0008	98	B+
S0013	90	B+
S0007	78	B+
S0024	75	B+
S0022	68	B+
S0018	66	B
S0004	59	B
S0006	56	B
S0011	56	B
S0012	56	B
S0017	55	C
S0009	54	C
S0003	50	C
S0023	45	C
S0016	34	C
S0021	26	D
S0005	23	D
S0010	23	D
S0019	23	D
S0020	18	D
S0015	12	D

Your help is much appreciated.

答案1

得分: 2

你可以使用窗口函数以几个步骤获得结果。使用rank()代替row_number(),这样可以处理排名

步骤1:使用窗口函数根据累积的AllocateQty计算起始和结束学生索引。在最后一个排名上,我们可以使用一个技巧,将最后一个排名的结束索引设置为任意大的数字(假设10000足够大以适应合理的课堂注册规模)。

这是步骤1的查询

select
    rank, 
    Grade,
    AllocateQty,
    coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + 1 as start_student_index,
    (case when AllocateQty = 0 then 10000 else coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + AllocateQty end)  as end_student_index
from
tblGrade
rank Grade AllocateQty start_student_index end_student_index
1 A 3 1 3
2 B+ 5 4 8
3 B 5 9 13
4 C 5 14 18
5 D 0 19 10000

步骤2:使用窗口函数和rank()计算student_grade_rank,并与grade_index进行连接。将连接结果限制在student_grade_rank在grade_start_index和grade_end_index之间。

这是完整查询

with gradeStudentIndex AS (
select
   rank, 
   Grade,
   AllocateQty,
   coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + 1 as start_student_index,
   (case when AllocateQty = 0 then 10000 else coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + AllocateQty end)  as end_student_index
from
    tblGrade
),
studentGradeRank AS (
select
    studentID,
    score,
    rank() over (order by score desc) as student_grade_rank
from
    tblStudentGrade     
)
select
    sr.studentID,
    sr.score,
    si.grade
from 
    StudentGradeRank sr
join
    gradeStudentIndex si
on
    sr.student_grade_rank BETWEEN si.start_student_index AND si.end_student_index
order by sr.student_grade_rank
studentID score grade
S0001 100 A
S0002 99 A
S0014 99 A
S0008 98 B+
S0013 90 B+
S0007 78 B+
S0024 75 B+
S0022 68 B+
S0018 66 B
S0004 59 B
S0006 56 B
S0011 56 B
S0012 56 B
S0017 55 C
S0009 54 C
S0003 50 C
S0023 45 C
S0016 34 C
S0021 26 D
S0005 23 D
S0010 23 D
S0019 23 D
S0020 18 D
S0015 12 D
英文:

You can use window function to get the result in a few step. Use rank() instead of row_number() so it can handle the tide.

Step 1. Use window function to calcuate start and end student index based on cumulative AllocateQty. On the last rank, we can use a trick to set end index of last rank to be arbitrary large number (let's say 10,000 is large enough for a reasonable classroom registration size)

Here is the step 1 query:

select
    rank, 
    Grade,
    AllocateQty,
    coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + 1 as start_student_index,
    (case when AllocateQty = 0 then 10000 else coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + AllocateQty end)  as end_student_index
from
tblGrade
rank Grade AllocateQty start_student_index end_student_index
1 A 3 1 3
2 B+ 5 4 8
3 B 5 9 13
4 C 5 14 18
5 D 0 19 10000

Step 2: Use window functiona and rank() to calculate student_grade_rank and join with grade_index. Bound the join result by student_grade_rank between grade_start_index and grade_end_index.

Here is the full query:

with gradeStudentIndex AS (
select
   rank, 
   Grade,
   AllocateQty,
   coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + 1 as start_student_index,
   (case when AllocateQty = 0 then 10000 else coalesce(sum(AllocateQty) over (order by rank ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) + AllocateQty end)  as end_student_index
from
    tblGrade
),
studentGradeRank AS (
select
    studentID,
    score,
    rank() over (order by score desc) as student_grade_rank
from
    tblStudentGrade     
)
select
    sr.studentID,
    sr.score,
    si.grade
from 
    StudentGradeRank sr
join
    gradeStudentIndex si
on
    sr.student_grade_rank BETWEEN si.start_student_index AND si.end_student_index
order by sr.student_grade_rank
studentID score grade
S0001 100 A
S0002 99 A
S0014 99 A
S0008 98 B+
S0013 90 B+
S0007 78 B+
S0024 75 B+
S0022 68 B+
S0018 66 B
S0004 59 B
S0006 56 B
S0011 56 B
S0012 56 B
S0017 55 C
S0009 54 C
S0003 50 C
S0023 45 C
S0016 34 C
S0021 26 D
S0005 23 D
S0010 23 D
S0019 23 D
S0020 18 D
S0015 12 D

答案2

得分: 1

以下代码可以实现:

    创建临时表 #TempTable (
        Rank int,
        Grade varchar(2),
        AllocateQty int,
        Remark varchar(50)
    );
    
    将数据插入 #TempTable (Rank, Grade, AllocateQty, Remark)
    VALUES (1, 'A', 3, ''),
           (2, 'B+', 5, ''),
           (3, 'B', 5, ''),
           (4, 'C', 5, ''),
           (5, 'D', 0, '剩余的');
    
    使用 Grades ([rank], [grade]) 作为公共表达式
    (
    	SELECT ROW_NUMBER() OVER (ORDER BY Rank)
    		  ,Grade
    	FROM #TempTable T
    	INNER JOIN
    	(
    		SELECT row_number() over(order by t1.number) as N
    		FROM master..spt_values t1 
    	) DS
    		ON T.[AllocateQty] >= DS.n
    )
    生成查询结果:
    SELECT S.*
    	  ,ISNULL(G.[grade], 'D')
    FROM
    (
       SELECT *
    	  ,ROW_NUMBER() OVER (ORDER BY Score, StudentID) AS [Rank]
    	FROM tblStudentGrade 
    ) S
    左连接 Grades G
    	ON S.[Rank] = G.[Rank]


首先,我们需要使用 `AllocateQty` 列复制成绩表,然后生成排名 - 分数对。接着,为每个学生生成排名,然后简单地将这两个数据源连接起来。

这只是一个基础版本,你需要根据实际情况进行改进。例如,如果两个或更多学生得分相同,我们按学生ID排序,但也许这些学生需要有相同的排名(在这种情况下可以使用 DENSE_RANK 作为例子)。
英文:

Something like below will work:

CREATE TABLE #TempTable (
    Rank int,
    Grade varchar(2),
    AllocateQty int,
    Remark varchar(50)
);

INSERT INTO #TempTable (Rank, Grade, AllocateQty, Remark)
VALUES (1, 'A', 3, ''),
       (2, 'B+', 5, ''),
       (3, 'B', 5, ''),
       (4, 'C', 5, ''),
       (5, 'D', 0, 'The rest');

WITH Grades ([rank], [grade]) AS
(
	SELECT ROW_NUMBER() OVER (ORDER BY Rank)
		  ,Grade
	FROM #TempTable T
	INNER JOIN
	(
		SELECT row_number() over(order by t1.number) as N
		FROM master..spt_values t1 
	) DS
		ON T.[AllocateQty] >= DS.n
)
SELECT S.*
	  ,ISNULL(G.[grade], 'D')
FROM
(
   SELECT *
	  ,ROW_NUMBER() OVER (ORDER BY Score, StudentID) AS [Rank]
	FROM tblStudentGrade 
) S
LEFT JOIN Grades G
	ON S.[Rank] = G.[Rank]

First, we need to duplicate the grades table using the AllocateQty column, and then generate ranks - marks pairs. Then, generate rank for each student and simply join the two data sources.

It's raw. You need to improve depending your real scenario. For example, if two or more students have the same score, we order by student ID, but maybe these students need to have one rank (use DENSE_RANK in such case for example).

huangapple
  • 本文由 发表于 2023年3月7日 14:38:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75658689.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定