SQL Server:根据另一个表中条目的频率选择条目

时间:2017-11-03 16:35:16

标签: sql-server select greatest-n-per-group

所以我使用的是SQL Server,我有两个类似于下面的表:


人员姓名
1个鲍勃
2比尔
3芭芭拉
4邦尼


人员ID类
1个数学
1科学
2数学
2英语
3科学
3英语
4英语
4数学
4科学

我需要编写一个查询,该查询返回占用最多类的人的名称和名称。因此,运行上述案例查询后的唯一结果应该是名称'Bonnie'。

如果是平局,则应返回多个名称。

我的尝试如下:

`Select People.Name
from People inner join Classes 
On People.PersonID = Classes.PersonID
Group by People.Name
Having max(Classes.PersonID)`

最后一行在SQL Server中不起作用,我不能为我的生活找出如何重新编写代码以使其正常运行。

有什么想法吗?

5 个答案:

答案 0 :(得分:1)

SELECT  TOP 1
        name
FROM    (
            SELECT  name,
                    COUNT(p.PersonID) as cnt
            FROM    People p
                    JOIN Classes c
                        ON p.PersonID = c.PersonID
            GROUP BY name
        ) a
ORDER BY cnt DESC

答案 1 :(得分:0)

试试这个

WITH CTE
AS
(
SELECT
    SeqNo = ROW_NUMBER() OVER(ORDER BY COUNT(1) DESC),
    P.PersonId,
    Cnt = COUNT(1)
    FROM Person p
        INNER JOIN Classes C
            ON P.PersonId = C.PersonId
        GROUP BY p.PersonId
)
SELECT
    *
    FROM Person P2
        WHERE EXISTS
        (
            SELECT 1 FROM CTE WHERE PersonId = p2.PersonId AND SeqNo = 1
        )

答案 2 :(得分:0)

T-SQL提供ranking functions,允许您根据字段或聚合计算排名。

鉴于这些表格:

declare @people table (personid int primary key,name nvarchar(20))
declare @classes table (personid int ,class nvarchar(20))

insert into @people(personid,name)
values
(1,'Bob'),
(2,'Bill'),
(3,'Barbara'),
(4,'Bonnie'),
(5,'Joe')

insert into @classes (personid,class)
values
(1,'Math'),
(1,'Science'),
(2,'Math'),
(2,'English'),
(3,'Science'),
(3,'English'),
(4,'English'),
(4,'Math'),
(4,'Science')
(5,'Science')

以下查询将根据所选课程数计算人员排名:

select p.name,count(*) As Classes,rank() over (order by count(*) desc) as Rank
from @classes c
inner join @people p on p.personid=c.personid
group by p.name

返回Bonnie有3个班级。所有其他学生在2个班级中排名第二:

name    Classes Rank
------- ------- ----
Bonnie  3       1
Barbara 2       2
Bill    2       2
Bob     2       2
Joe     1       5
如果有关系,

RANK将跳过职位。这就是Joe排名为5的原因。

您无法在WHERE或HAVING子句中使用排名功能。要仅返回您需要使用子查询或CTE的第一个学生,例如:

select name,classes
from (
    select p.name,count(*) As Classes,rank() over (order by count(*) desc) as Rank
    from @classes c
    inner join @people p on p.personid=c.personid
    group by p.name
) r
where rank=1

或者

;with r as (
    select p.name,count(*) As Classes,rank() over (order by count(*) desc) as Rank
    from @classes c
    inner join @people p on p.personid=c.personid
    group by p.name
)
select name,classes
from r
where rank=1

两个查询都将返回:

name    Classes
------- -------
Bonnie  3      

如果你想找到N个最好的学生,你应该使用DENSE_RANK并返回排名小于或等于N的行。DENSE_RANK Joe的排名将是3。

以下查询将返回前两位的学生:

with r as (
    select p.name,count(*) As Classes,dense_rank() over (order by count(*) desc) as Rank
    from @classes c
    inner join @people p on p.personid=c.personid
    group by p.name
)
select name,classes
from r
where rank<=2

答案 3 :(得分:0)

使用TOP查询获取大多数类的人员ID。然后从人员表中选择人员姓名:

select name 
from people
where people_id in
(
  select top(1) with ties person_id
  from classes
  group by person_id
  order by count(*) desc
);

答案 4 :(得分:0)

好的,我通过Having COUNT(*) >= ALL (Select..)命令行找到了最有效的方法 代码如下:
Select People.Name as 'Most Classes Taken:' from People inner join Classes On People.PersonID = Classes.PersonID Group by People.Name Having count(*)>=ALL (Select count(*) from Classes group by Classes.PersonID)