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

Posted

技术标签:

【中文标题】SQL Server:根据另一个表中条目的频率选择条目【英文标题】:SQL Server: Select entry based on frequency of entries in another table 【发布时间】:2017-11-03 16:35:16 【问题描述】:

所以我使用的是 SQL Server,并且我有两个类似于下面的表: 个人 ID    姓名 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 中不起作用,我终其一生都无法弄清楚如何重新编写代码以使其正常运行。

有什么想法吗?

【问题讨论】:

你的 HAVING 是不完整的。您需要添加类似 = 4 的内容,但它也存在逻辑错误,因为您不知道 PersonID。因此,您不想查看该列。你想看看计数。 【参考方案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

【讨论】:

是的,这非常有助于澄清事情。【参考方案2】:

试试这个

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
        )

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

使用 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
);

【讨论】:

【参考方案5】:

好的,我通过Having COUNT(*) &gt;= 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)

【讨论】:

以上是关于SQL Server:根据另一个表中条目的频率选择条目的主要内容,如果未能解决你的问题,请参考以下文章

添加列通过从sql Server中的另一个表中选择所有项目来选择表

sql怎样把一个表的数据更新到另一个表

根据表中另一个现有列的内容更改 SQL Server 中的现有列

Sql-Server触发器,根据条件匹配另一个表中的字段

如何获取列出表中条目的次数

SQL Server:根据来自其他 2 个表的子查询从表中选择