如何在这种情况下重写一个选择查询

时间:2009-12-27 19:37:14

标签: sql sql-server

以下是父/子关系中的两个表。 我需要做的是选择有平均分的学生:

CREATE TABLE dbo.Students(
 Id int NOT NULL,
 Name varchar(15) NOT NULL,
 CONSTRAINT PK_Students PRIMARY KEY CLUSTERED 
(

CREATE TABLE [dbo].[Results](
 Id int NOT NULL,
 Subject varchar(15) NOT NULL,
 Mark int NOT NULL
) 

ALTER TABLE [dbo].[Results]  WITH CHECK ADD  CONSTRAINT [FK_Results_Students] FOREIGN KEY([Id])
REFERENCES [dbo].[Students] ([Id])

我写了一个这样的查询:

SELECT   name , coalesce(avg(r.[mark]),0) as Avmark
FROM  students s
 LEFT JOIN results r ON s.[id]=r.[id]
GROUP BY s.[name]
ORDER BY ISNULL(AVG(r.[mark]),0) DESC;

但结果是所有在那里的学生都按照顺序排列。我需要的是限制结果集与平均分数最高的学生相同,即如果是两个学生,平均分为50和1我需要只显示那些50岁的学生。如果只有一个学生的平均分数最高 - 只有他必须出现在结果集中。我怎么能以最好的方式做到这一点?

4 个答案:

答案 0 :(得分:1)

SQL Server 2005+,使用CTE:

WITH grade_average AS (
   SELECT r.id,
          AVG(r.mark) 'avg_mark'
     FROM RESULTS r
 GROUP BY r.id),
    highest_average AS (
   SELECT MAX(ga.avg_mark) 'highest_avg_mark'
     FROM grade_average ga)
SELECT DISTINCT
       s.name,
       ga.avg_mark
  FROM STUDENTS s
  JOIN grade_average ga ON ha.id = s.id
  JOIN highest_average ha ON ha.highest_avg_mark = ga.avg_mark

非CTE等效物:

SELECT DISTINCT
       s.name,
       ga.avg_mark
  FROM STUDENTS s
  JOIN (SELECT r.id,
               AVG(r.mark) 'avg_mark'
          FROM RESULTS r
      GROUP BY r.id) ga ON ha.id = s.id
  JOIN SELECT MAX(ga.avg_mark) 'highest_avg_mark'
         FROM (SELECT r.id,
                      AVG(r.mark) 'avg_mark'
                 FROM RESULTS r
             GROUP BY r.id) ga) ha ON ha.highest_avg_mark = ga.avg_mark

答案 1 :(得分:0)

如果您使用的是相对较新版本的MS SQL服务器,则可以使用WITH来简化编写:

WITH T AS (
    SELECT
        name,
        coalesce(avg(r.[mark]),0) as mark
    FROM students s
    LEFT JOIN results r ON s.[id]=r.[id]
    GROUP BY s.[name])
SELECT name as 'ФИО', mark as 'Средний бал'
FROM T
WHERE T.mark = (SELECT MAX(mark) from T)

答案 2 :(得分:0)

这么简单吗?适用于所有版本的SQL Server 2000 +

SELECT TOP 1 WITH TIES
   name, ISNULL(avg(r.[mark]),0) as AvMark
FROM
   students s
   LEFT JOIN
   results r ON s.[id]=r.[id]
GROUP BY
   s.[name]
ORDER BY
   ISNULL(avg(r.[mark]),0) DESC;

答案 3 :(得分:-1)

SELECT name as 'ФИО', 
coalesce(avg(r.[mark]),0) as 'Средний бал' 
FROM students s 
LEFT JOIN results r 
ON s.[id]=r.[id] 
GROUP BY s.[name] 
HAVING AVG(r.[mark]) >= 50
ORDER BY ISNULL(AVG(r.[mark]),0) DESC

about HAVING clause