英文:
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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论