Как сделать «оценку» в чистом (т.е. ANSI) SQL - PullRequest
0 голосов
/ 22 июня 2010

У меня есть таблица, которая выглядит примерно так:

CREATE TABLE student_results (целое число id, имя varchar (32), число с плавающей запятой);

Позволяет сделать следующие два предположения:

  1. Предположим, что оценка изменяется от 0 до максимум 100.
  2. Предположим, что я хочу оценивать студентов по «размерам шагов» 10

поэтому я хочу применить следующую оценку:

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.Если мне нужно выбрать базу данных, то в порядке УМЕНЬШЕНИЯ предпочтения это должно быть:

  • PostgreSQL
  • MySQL

Может кто-нибудь пожалуйстаобъясните, как я могу написать SQL-запрос, который выполняет такую ​​оценку, используя приведенную выше таблицу в качестве примера?

[Edit]

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

Ответы [ 4 ]

1 голос
/ 23 июня 2010

Таким образом, вы можете сделать это более общим, но оценки будут в обратном порядке, начиная с 1 до N, то есть

  • 0-10 Grade1
  • 10-20 класс2
  • 20-30 класс 3
  • 30-40 класс 4
  • ...

Например, используя значения шаг 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';
1 голос
/ 22 июня 2010

Есть несколько вариантов:

1) создать таблицу с оценками (min, max) и объединиться на этой таблице

SELECT score, grades.grade
FROM table 
     INNER JOIN grades ON table.score >= grades.min AND table.score <= grades.max

2) создать временную таблицу (или дажевыберите из ДВОЙНОГО) и присоединитесь к нему, например, в приведенных выше вместо оценок вы можете написать подзапрос

(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) создать пользовательскую функцию (но это будет зависеть от RDBMS)

1 голос
/ 22 июня 2010

Как насчет этого? (Оказывается, я использовал @steps, как и в количестве шагов, вместо @step. Если вы укажете @step, @steps можно рассчитать как @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.
1 голос
/ 22 июня 2010

как то так?

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 размер больше, чем другие диапазоны?)

Редактировать

Переименован в @step в @stepsize для ясности для каждого ивара (@step может быть неверно истолкован как число шагов)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...