我有一张看起来像这样的表:
CREATE TABLE student_results(id integer,name varchar(32),score float);
让我们做出以下两个假设:
所以我想申请以下评分:
Score Grade Awarded
0-10 GRADE9
10-20 GRADE8
20-30 GRADE7
30-40 GRADE6
40-50 GRADE5
50-60 GRADE4
60-70 GRADE3
70-80 GRADE2
80-90 GRADE1
99-100 GENIUS
我想编写一个SQL查询,它接受以下输入参数:
lowest score: 0 in this example
highest score: 100 in this example
'step' size: 10 in this example
与以往一样,如果可能,我想使用ANSI SQL编写这样的查询。如果我必须选择一个数据库,那么按照减少优先顺序,它必须是:
有人可以解释一下如何使用上表作为示例来编写执行此类评分的SQL查询吗?
[编辑]
Sample input data
1, 'homer', 10.5
2. 'santas little helper', 15.2
3, 'bart', 20.5
4, 'marge', 40.5
5. 'lisa', 100
我将有一个SQL函数grade_rank() - 对学生进行排名:
函数grade_rank()的参数是:
1st argument: LOWEST possible score value
2nd argument: HIGHEST possible score value
3rd argument: step size, which determines the levels/divisions between the ranks
select id, name, grade_rank(0,100, 10) grade from student_scores;
输出(基于上面的输入)应为:
1, homer, GRADE9
2. santas liitle helper GRADE9
3, bart, GRADE8
4, marge, GRADE6
5. lisa, GENIUS
答案 0 :(得分:1)
这样的事情?
SELECT
[name],
score,
CASE
WHEN score > @max - @stepsize THEN 'GENIUS'
ELSE CONCAT('GRADE',
CAST(
FLOOR((@max - score)/@stepsize -
CASE score
WHEN @min THEN 1
ELSE 0
END CASE
) as char(3)
)
)
END CASE
FROM
student_results
你可能需要稍微调整一下 - 我不太明白最小部分(它是否仅用于因为最后一个范围比其他范围大1个?)
修改强>
为了每个Ivar的清晰度,将@step重命名为@stepsize(@step可能被误解为步数)
答案 1 :(得分:1)
有几个选择:
1) 创建一个包含成绩(分钟,最大)的表并加入该表
SELECT score, grades.grade
FROM table
INNER JOIN grades ON table.score >= grades.min AND table.score <= grades.max
2) 创建一个临时表(甚至从DUAL中选择)并加入它,例如在上面而不是成绩中你可以编写子查询
(SELECT 0 as MIN, 10 as max, 'GRADE9' as grade FROM DUAL
UNION ALL
SELECT 11 as MIN, 20 as max, 'GRADE8' as grade FROM DUAL
UNION ALL
...
SELECT 91 as min, 100 as max, 'GENIUS' as grade FROM DUAL
) AS grades
3) 使用案例
SELECT score,
CASE WHEN score = 0 THEN 'GRADE9'
WHEN score >= 1 AND score <= 90 THEN 'GRADE' || (9 - (score-1) / 10)
WHEN score >= 91 THEN 'GENIUS'
ELSE 'ERROR'
END grade
FROM table
(注意在上面的查询中你可以用0,100和10代替最低,最高和步骤来获得动态sql)
4) 创建user function(但这将获得RDBMS特定的)
答案 2 :(得分:1)
这个怎么样?
(原来我已经使用了@steps,就像步数一样,而不是@step。如果你想指定@step,@ step可以计算为@steps = (@highest-@lowest)/@step
SET @lowest = 0;
SET @highest = 100;
SET @steps = 10;
SELECT
name,
CASE
WHEN score >= (@highest-@steps) THEN 'GENIUS'
ELSE
CONCAT(
'GRADE',
@steps-FLOOR((score-@lowest)/((@highest-@lowest)/@steps))-1)
END
FROM
student_results
每当您通过下一步时,这将为您提供新的成绩。
0-9.999 => GRADE1
10-19.999 => GRADE2
etc.
答案 3 :(得分:1)
通过这种方式你可以做到更一般,但等级将是相反的顺序,从1到N,即
例如使用值 第10步 得分43
此算法
SELECT (((score-1)-((score-1) % step))/step)+1
将返回5
您无需知道最高分数。如果最高分数为100,则无法执行高于100的分数,您只需确定步骤的大小即可。例如,如果您想要步长为25.知道最高分为100,则将有4个年级。因此,通过将步骤级别设置为25而不是10,结果将为2,即2级。
SELECT (((43-1)-((43-1) % 25))/25)+1
也许你的预期并不正确,但也许通用到足以使用。这是函数在SQL中的样子。
CREATE OR REPLACE FUNCTION grade_rank(IN score integer, IN step integer, OUT rank integer)
AS 'SELECT ((($1-1)-(($1-1) % $2))/$2)+1'
LANGUAGE 'SQL';
现在调用此函数
select * from grade_rank(43,10)
返回5.
这是plpgsql的等价物:
CREATE OR REPLACE FUNCTION grade_rank(IN score integer, IN step integer)
RETURNS integer AS
$BODY$
DECLARE rank integer;
BEGIN
SELECT (((score-1)-((score-1) % step))/step)+1 INTO rank;
RETURN rank;
END;
$BODY$
LANGUAGE 'plpgsql';