Как написать SQL-запрос, который получает высокие оценки по сравнению с недавним подмножеством оценок - см. Объяснение - PullRequest
1 голос
/ 19 января 2011

Приведена таблица ответов с колонками:

Имя пользователя, Номер урока, Номер вопроса, Ответ, Оценка, Метка времени

Как мне выполнить запрос, который показывает, какие пользователи получили оценку 90 или выше при первой попытке ответить на каждый вопрос в последних 5 уроках? «последние 5 уроков» являются скорее ограничивающим условием, чем требованием, поэтому, если они полностью закончили только 1 урок, но все свои первые попытки выполнили правильно для каждого вопроса, то они должны быть включены в результаты. Мы просто не хотим оглядываться на 5 уроков.

О данных: пользователи могут быть на разных уроках. Некоторые пользователи, возможно, еще не завершили пять уроков (например, могут быть только на уроке 3). Каждый урок имеет разное количество вопросов. У пользователей разные пути уроков, поэтому они могут пропускать некоторые номера уроков или даже выполнять уроки не по порядку.

Поскольку это, по-видимому, проблема преобразования временно неоднородных / прерывистых значений в однородные / непрерывные значения для пользователя, я думаю, что я могу решить большую часть проблемы с помощью пары функций ранжирования. Условная спецификация оценки выше 90 для «первой попытки на каждый вопрос в последних 5 уроках» также сложна, потому что количество выполненных вопросов варьируется для каждого пользователя.

Пока ...

В качестве отправной точки или намека на то, что, возможно, должно произойти, я преобразовал метку времени в «AttemptNumber» для каждого вопроса, используя «row_number () over (разделение по имени пользователя, LessonNumber, QuestionNumber, порядок по метке времени) как AttemptNumber».

Я также пытаюсь преобразовать LessonNumber из абсолютного значения в непрерывное ранжированное значение для отдельных пользователей. Я мог бы использовать «density_rank () over (разделение по порядку имени пользователя по LessonNumber desc) как LessonRank», но это предполагает, что порядок уроков завершен соответствует порядку LessonNumber, что, к сожалению, не всегда так. Тем не менее, давайте предположим, что это так, поскольку у меня есть способ получения такого числа через пару соединений, поэтому я могу использовать описанное преобразование density_rank для выбора «последних 5 завершенных уроков» (т. Е. LessonRank <= 5 ). </p>

Для условия> 90, я думаю, я могу преобразовать счет в целое число, чтобы оно равнялось «1», если> = 90, и «0», если <90. Затем я могу ввести фразу типа «группа» с именем пользователя, имеющим SUM (Score) = COUNT (Score). ", Который выберет только тех пользователей, у которых все оценки равны 1. </p>

Любые решения или предложения будут оценены.

Ответы [ 3 ]

0 голосов
/ 20 января 2011

Сначала необходимо определить 5 лучших уроков для каждого пользователя, используя временную метку для определения приоритетов уроков, затем вы можете ограничить счет. Попробуйте:

Select username
from table t inner join
(select top 5 username, lessonNumber
 from table
 order by timestamp desc) l 
on t.username = l.username and t.lessonNumber = l.lessonNumber
from table
where score >= 90
0 голосов
/ 20 января 2011

Вы отдали решение:

SELECT DISTINCT Username
FROM Results 
WHERE Username NOT in (
    SELECT DISTINCT Username
    FROM (
        SELECT
            r.Username,r.LessonNumber, r.QuestionNumber, r.Score, r.Timestamp
            , row_number() over (partition by r.Username,r.LessonNumber,r.QuestionNumber order by r.Timestamp) as AttemptNumber
            , dense_rank() over (partition by r.Username order by r.LessonNumber desc) AS LessonRank
        FROM Results r
        ) as f
    WHERE LessonRank <= 5 and AttemptNumber = 1 and Score < 90
)

Что касается LessonRank, я использовал именно то, что вы описали, поскольку неясно, как иначе упорядочить уроки: метка времени первой попытки первого вопроса урока? Или отметка времени первой попытки любого вопроса урока? Или просто первая (или самая последняя?) Временная метка любого результата любого вопроса урока?

Самый внутренний Select добавляет все AttemptNumber и LessonRank, как вы предоставили.

В следующем Select сохраняются только результаты, из-за которых пользователь не попадет в окончательный список - все первые попытки с недостаточным количеством баллов за последние 5 уроков. В итоге получается список пользователей, которых мы не хотим отобразить в конечном результате.

Следовательно, в самом внешнем Select мы можем выбрать всех пользователей, которые не в списке исключений. В основном все остальные пользователи, которые ответили на любой вопрос.

РЕДАКТИРОВАТЬ: Как часто, вторая попытка должна быть лучше ...

Еще один РЕДАКТИРОВАТЬ :

Вот версия, включающая ваши замечания в комментариях.

SELECT Username
FROM 
(
    SELECT Username, CASE WHEN Score >= 90 THEN 1 ELSE 0 END AS QuestionScoredWell
    FROM (
        SELECT
            r.Username,r.LessonNumber, r.QuestionNumber, r.Score, r.Timestamp
            , row_number() over (partition by r.Username,r.LessonNumber,r.QuestionNumber order by r.Timestamp) as AttemptNumber
            , dense_rank() over (partition by r.Username order by r.LessonNumber desc) AS LessonRank
        FROM Results r
        ) as f
    WHERE LessonRank <= 5 and AttemptNumber = 1
) as ff
Group BY Username
HAVING MIN(QuestionScoredWell) = 1

Я использовал предложение Having с выражением MIN для вычисленного значения QuestionScoredWell.

При сравнении планов выполнения для обоих запросов этот запрос на самом деле быстрее. Не уверен, однако, является ли это частично из-за малого количества строк данных в моей таблице.

0 голосов
/ 19 января 2011

Случайные предложения:

1

Условная спецификация оценки выше 90 для «первой попытки на каждый вопрос в последних 5 уроках» также хитрая, потому что количество вопросов варьируется для каждого пользователя.

эквивалентно

Не существует первой попытки со счетом <= 90 последних 5 уроков </p>

, который кажется мне немного легче получить с помощью NOT EXISTS подзапроса.

2

Первая попытка такая же, как where timestamp = (select min(timestamp) ... )

...