我有一个数据库,我需要查询从一个表中获取记录,然后在另一个表上查找以查看该值是否存在。该表可能会返回多个记录,我想要一个具有最新日期的记录。
所以表1基本上是:
ID (Primary Key)
Name
Test_Score
表2是
Test_Id (Primary)
Student_ID (Foreign Key)
Test_Score
Test_Date
当我浏览记录时,如果表2中没有针对Student_id的测试,我想使用表1中的分数,否则我想使用表2中最近日期的分数。我所有这些都在C#代码中工作,但客户希望它在存储过程中用于报告目的,并且我看到一些性能问题,因为表非常大。此外,这个基本示例实际上会针对多个表多次发生。
我确信有一种优雅的方法可以快速有效地进行此操作,但除了使用光标外,我似乎无法想出任何东西。
有人知道直截了当的解决方案吗?
答案 0 :(得分:3)
不是百分之百确定语法细节,但是像这样:
select table1.Name, ISNULL(table2.Test_Score, table1.Test_Score)
from
table1
left outer join table2
on table1.id = table2.Student_ID
AND table2.Test_Date = (
select max(x.Test_Date)
from table2 x
where table1.id = x.Student_ID
group by x.Student_ID)
如果子查询不允许,请将其移动到where子句。 (对不起,我现在无法尝试。)
仅当Test_Date是唯一的时,查询才有效。如果没有,你会得到重复的结果。那么你应该使用Group By
select table1.Name, min(ISNULL(table2.Test_Score, table1.Test_Score))
from
table1
left outer join table2
on table1.id = table2.Student_ID
AND table2.Test_Date = (
select max(x.Test_Date)
from table2 x
where table1.id = x.Student_ID
group by x.Student_ID)
group by table1.id, table1.Name
答案 1 :(得分:2)
Stefan Steinegger基本上有正确的答案。
通过功能分解让自己更轻松:编写一个视图,为每个学生提供最近日期的行。
然后将外连接到学生表(问题中的表1),并使用isnull或coalesce获取表1中没有行的测试分数。
答案 2 :(得分:1)
如果您使用的是Sql Server 2005,那么公用表表达式(CTE)可提供一个优雅的解决方案。您为每个学生创建一个CTE,其中包含最新的考试成绩,然后将其加入学生表。如果测试表中存在结果,则使用学生表中的分数。
我假设您的表分别称为Student和TestResult,并且还假设test_id是自动递增ID
WITH RecentResults as (
SELECT student_id,
test_score
FROM TestResult tr
WHERE tr.test_id = (SELECT MAX(test_id) FROM TestResult WHERE student_id = tr.student_id)
)
SELECT s.ID as 'Student ID',
isnull(rr.test_score, s.test_score)
FROM Students s LEFT JOIN RecentResults rr ON s.ID = rr.student_id
我无法在此计算机上测试代码 - 如果您提供数据库架构将更容易完善。
答案 3 :(得分:1)
在这里,在SQL 2005上测试解决方案,可以避免视图,但我同意它提高了清晰度
create table students (id int primary key, name nvarchar(50), score int)
create table scores (test_id int, student_id int, score int, date datetime)
insert students values (1, 'bob', 1)
insert students values (2,'bill', 55)
insert scores values (22,1,88,getdate())
insert scores values (23,1,88,getdate() + 1 )
insert scores values (23,1,89,getdate() + 2 )
go
create view latest_scores
as
select scores.student_id, scores.date, score
from scores
join
(
select student_id, date = max(date) from scores
group by student_id
) maxDates on maxDates.student_id = scores.student_id and maxDates.date = scores.date
go
select Id, isnull(l.score, s.score) from students s
left join latest_scores l on student_id = id