sql - вернуть максимальное значение за период в двух таблицах - PullRequest
0 голосов
/ 03 июня 2011

Вот упрощенная версия моей задачи:

У меня есть две таблицы:

Студенты :

ST_STUDENT_ID  NAME   ST_DATE_TAKEN
-------------  -----  -------------
1              Jim    2011-01-01
2              Fred   2011-01-02
3              Sarah  2011-01-03
4              Nancy  2001-02-04

SCORES :

SC_STUDENT_ID  SC_SCORE
-------------  --------
1              97
2              97
3              95
4              97

Мне нужно набрать наибольшее количество баллов за месяц (скажем, в январе).Тем не менее, мне нужен только один ученик, даже если несколько учеников получили этот балл, и этот балл также мог существовать вне моего основного месяца, так что это усложняет мой запрос.Единственный способ, которым я мог это сделать, - это повторить все мои критерии в каждом вложенном подзапросе.Есть ли способ лучше.Это было не так уж и страшно, но в моей реальной проблеме, где критерии намного сложнее и объединены во многих таблицах, дублирование - это боль, плюс стоимость становится довольно большой.

SELECT ST_STUDENT_ID, ST_TIMESTAMP, SC_SCORE
FROM STUDENTS 
JOIN SCORES
  ON ST_STUDENT_ID = SC_STUDENT_ID
WHERE ST_STUDENT_ID = (
  SELECT MAX(ST_STUDENT_ID)
  FROM STUDENTS
  JOIN SCORES
    ON ST_STUDENT_ID = SC_STUDENT_ID
  WHERE ST_TIMESTAMP > '2011-01-01'
    AND ST_TIMESTAMP < '2011-02-01'
    AND SC_SCORE IS NOT NULL
    AND SC_SCORE = (
      SELECT MAX(SC_SCORE)
        FROM STUDENTS
      JOIN SCORES
        ON ST_STUDENT_ID = SC_STUDENT_ID
      WHERE ST_TIMESTAMP > '2011-01-01'
        AND ST_TIMESTAMP < '2011-02-01'))

Ответы [ 2 ]

1 голос
/ 03 июня 2011

(Предполагается, что SQL Server 2005 или более поздняя версия, или другая RDMBS, которая поддерживает CTE и оконные функции)

Что-то вроде:

;With OrderedScores as (
SELECT
    ST_STUDENT_ID,
    ST_TIMESTAMP,
    SC_SCORE,
    ROW_NUMBER() OVER (ORDER BY SC_SCORE desc,newid()) as rn /* Ordered randomly within same score */
FROM
    STUDENTS
        join
    SCORES
        on ST_STUDENT_ID = SC_STUDENT_ID
WHERE
    ST_TIMESTAMP >= '20110101' and
    ST_TIMESTAMP < '20110201'
)
select * from OrderedScores where rn = 1

Очевидно, что вы можете поиграть с критериями в пределах ORDER BY оконной функции, чтобы определить, какого ученика вы выбираете при наличии связей (в приведенном выше примере это случайный случай; опять же, если предположить, что SQL Server - если другая СУБД, заменить на что-то другое)

Кроме того, я думаю, что у меня правильные критерии даты здесь - в исходном запросе у вас есть один набор критериев, который использует > и < (т.е. исключая Джима), а в другом вы используйте <= и >=, которые могут включать учащегося, прошедшего тестирование 1 февраля.

1 голос
/ 03 июня 2011

Если вам нужен только один балл, и ваш период времени будет явно указан в запросе, что насчёт этого?

SELECT TOP 1 ST_STUDENT_ID, ST_TIMESTAMP, SC_SCORE
FROM STUDENTS 
JOIN SCORES ON ST_STUDENT_ID = SC_STUDENT_ID
WHERE ST_TIMESTAMP >= '2011-01-01'
AND ST_TIMESTAMP <= '2011-02-01'
ORDER BY SC_SCORE DESC, ST_STUDENT_ID DESC

Этот синтаксис должен работать для MS SQL Server - разные РСУБД имеют немного разные синтаксисы для концепции "TOP 1".

[Я вижу из вашего последующего комментария, что вы используете DB2 - в этом случае синтаксис, по-видимому, FETCH FIRST 1 ROWS ONLY.]

Обратите внимание, что я следую логике в вашем примере, которая подразумевает, что студент с самым высоким ID имеет преимущество. Хороший стимул для поздней регистрации на занятие; -)

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