以下是我的问题的简化版本:
我有两张桌子:
学生:
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'))
答案 0 :(得分:1)
如果您只需要一个分数,并且您的时间段将明确传递到查询中,那么这样的事情呢?
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 - 不同的RDBMS对“TOP 1”概念的语法略有不同。
[我在后面的评论中看到你正在使用DB2 - 在这种情况下,语法显然是FETCH FIRST 1 ROWS ONLY
。]
请注意,我正在遵循您示例中的逻辑,这意味着具有最高ID的学生优先。上课迟到的良好动机; - )
答案 1 :(得分:1)
(假设SQL Server 2005或更高版本,或支持CTE和窗口函数的其他RDMBS)
类似的东西:
;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 - 如果是另一个RDBMS,{{ 1}}应替换为其他东西)
此外,我认为我的日期条件正确无误 - 在原始查询中,您有一组使用newid()
和>
的标准(因此不包括Jim),以及另一方面,你使用<
和<=
,其中可能包括2月1日测试过的学生。