Sql 带聚合的子查询

Sql 带聚合的子查询,sql,sql-server,sql-server-2017,Sql,Sql Server,Sql Server 2017,我很难找到如何从员工最多的表中获取项目编号或项目名称 create table Pro_works_on ( EID char(9) , PNO char(9) , Pro_HOURS smallint not null, constraint pk_Pro_works_on primary key(EID,PNO), ); SELECT p.PNO FROM Pro_works_on AS p ,( SELECT COUNT(p.

我很难找到如何从员工最多的表中获取项目编号或项目名称

create table Pro_works_on
(
    EID char(9) ,
    PNO char(9) ,
    Pro_HOURS smallint not null,
    constraint pk_Pro_works_on primary key(EID,PNO),
);

SELECT
  p.PNO
FROM
  Pro_works_on AS p
 ,(
    SELECT
      COUNT(p.EID) AS numOfEmployee
     ,p.PNO
    FROM
      Pro_works_on AS p
    GROUP BY
      p.PNO
  ) AS L
WHERE
  MAX(L.numOfEmployee) = COUNT(p.EID);
它会产生以下错误:

子查询返回了多个值。当子查询在=、!=、=或者当子查询用作表达式时


如果您想要一行,请使用
orderby
和某种限制子句。在标准SQL中:

select p.PNO, count(*) as numOfEmployee 
from Pro_works_on p
group by p.PNO
order by count(*) desc
fetch first 1 row only;
在SQL Server中,您可以使用带领带的
top(1)或
top(1):

select top (1) p.PNO, count(*) as numOfEmployee 
from Pro_works_on p
group by p.PNO
order by count(*) desc;

如果您想要一行,请使用
orderby
和某种限制子句。在标准SQL中:

select p.PNO, count(*) as numOfEmployee 
from Pro_works_on p
group by p.PNO
order by count(*) desc
fetch first 1 row only;
在SQL Server中,您可以使用带领带的
top(1)或
top(1):

select top (1) p.PNO, count(*) as numOfEmployee 
from Pro_works_on p
group by p.PNO
order by count(*) desc;

对于聚合结果,您应该将having用作filter,而不是where

select L.PNO 
    from Pro_works_on p, (
    select count(p.EID) as numOfEmployee
    ,p.PNO
    from Pro_works_on p
    group by p.PNO) L
HAVING  MAX(L.numOfEmployee)=numOfEmployee
但可能是您可以使用一种更简单的方法,通过使用order by和limit 1来避免与组相关的问题

    select L.PNO 
    (
        select count(p.EID) as numOfEmployee
        , p.PNO
        from Pro_works_on p
        group by p.PNO
    ) L 
    order by numOfEmployee DESC 
    LIMIT 1 

对于聚合结果,您应该将having用作filter,而不是where

select L.PNO 
    from Pro_works_on p, (
    select count(p.EID) as numOfEmployee
    ,p.PNO
    from Pro_works_on p
    group by p.PNO) L
HAVING  MAX(L.numOfEmployee)=numOfEmployee
但可能是您可以使用一种更简单的方法,通过使用order by和limit 1来避免与组相关的问题

    select L.PNO 
    (
        select count(p.EID) as numOfEmployee
        , p.PNO
        from Pro_works_on p
        group by p.PNO
    ) L 
    order by numOfEmployee DESC 
    LIMIT 1 

为了让项目拥有最多的员工,我会:

with
x as (
  select
    pno,
    count(eid) as tot_emp
  from pro_works_on
  group by pno
),
y as (
  select max(tot_emp) as max_emp from x
)
select 
  x.pno
from x
join y on y.max_emp = x.tot_emp

为了让项目拥有最多的员工,我会:

with
x as (
  select
    pno,
    count(eid) as tot_emp
  from pro_works_on
  group by pno
),
y as (
  select max(tot_emp) as max_emp from x
)
select 
  x.pno
from x
join y on y.max_emp = x.tot_emp

把你的问题分解成几个步骤

首先,您需要知道每个项目分配了多少员工。这样你就知道哪家公司的员工最多了。要做到这一点,请将
COUNT
groupby
一起使用

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
SELECT TOP(1) WITH TIES
  p.PNO
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;
接下来,使用
orderby
,让您的查询将结果按您想要的顺序排列。你想让员工最多的项目排在第一位,所以把他们放在
DESC
结束顺序中

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;
最后,因为您只关心员工最多的一个项目,所以添加一个行限制器。在SQL Server中,可以使用
TOP(N)
表达式来实现这一点。而且,由于您只关心项目编号,而不关心员工的实际数量,因此您可以从结果中提取
计数
,并将其按
的顺序保留

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
SELECT TOP(1) WITH TIES
  p.PNO
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;

编辑:根据OP在评论中提出的问题添加了带领带的

将问题分解为几个步骤

首先,您需要知道每个项目分配了多少员工。这样你就知道哪家公司的员工最多了。要做到这一点,请将
COUNT
groupby
一起使用

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
SELECT TOP(1) WITH TIES
  p.PNO
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;
接下来,使用
orderby
,让您的查询将结果按您想要的顺序排列。你想让员工最多的项目排在第一位,所以把他们放在
DESC
结束顺序中

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;
最后,因为您只关心员工最多的一个项目,所以添加一个行限制器。在SQL Server中,可以使用
TOP(N)
表达式来实现这一点。而且,由于您只关心项目编号,而不关心员工的实际数量,因此您可以从结果中提取
计数
,并将其按
的顺序保留

SELECT 
  p.PNO, COUNT(p.EID) AS numOfEmployee
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
SELECT TOP(1) WITH TIES
  p.PNO
FROM
  Pro_works_on AS p
GROUP BY
  p.PNO
ORDER BY COUNT(p.EID) DESC;

编辑:根据OP在评论中提出的问题添加了带有关系的

如果需要返回多个项目(如果每个项目的员工人数最多),则可以使用窗口函数进行聚合,然后按此进行筛选

SELECT *
FROM (
    SELECT p.PNO
        , count(*) AS empCount
        , RANK() OVER (ORDER BY count(*) DESC) AS r
    FROM Pro_works_on p
    GROUP BY p.PNO
) s1
WHERE r = 1

这将按顺序对所有员工进行排名,并将所有最高员工计数的排名设置为1。然后只需选择所有排名为1的

如果需要返回多个项目(如果每个项目都有最多的员工),则可以使用窗口函数进行聚合,然后按此进行筛选

SELECT *
FROM (
    SELECT p.PNO
        , count(*) AS empCount
        , RANK() OVER (ORDER BY count(*) DESC) AS r
    FROM Pro_works_on p
    GROUP BY p.PNO
) s1
WHERE r = 1


这将按顺序对所有员工进行排名,并将所有最高员工计数的排名设置为1。然后只需选择所有排名为1的

但它不能满足我的需要。我需要的是员工人数最多的项目。这里只给我每个项目的编号。@MikaAzulay。你运行过这个查询吗?它为项目提供了最多的员工。对于SQL Server,这将需要在
FETCH
语句之前使用
OFFSET 0行
。RE:。它将在
TOP
上提供一些性能改进。(我不认为它能用领带做
,但它可以复制)。@Shawn。您是否有使用
OFFSET/FETCH
改进性能的参考资料?但它没有回答我的需要。我需要的是员工人数最多的项目。这里只给我每个项目的编号。@MikaAzulay。你运行过这个查询吗?它为项目提供了最多的员工。对于SQL Server,这将需要在
FETCH
语句之前使用
OFFSET 0行
。RE:。它将在
TOP
上提供一些性能改进。(我不认为它能用领带做
,但它可以复制)。@Shawn。您是否有关于使用
OFFSET/FETCH
提高性能的参考?它说:“Pro\u works\u on.PNO”列在选择列表中无效,因为它未包含在聚合函数或GROUP BY子句中。仍然:“L.numOfEmployee”列在HAVING子句中无效,因为它未包含在聚合函数或GROUP BY子句中函数或GROUP BY子句。它表示:列“Pro_works_on.PNO”在选择列表中无效,因为它未包含在聚合函数或GROUP BY子句中。仍然:列“L.numOfEmployee”在HAVING子句中无效,因为它未包含在聚合函数或GROUP BY子句中。您使用哪种SQL你在用什么?这个错误看起来有点像MS SQL Server,但我不确定。或者MySQL,或者DB2。microsoft SQL management studioSQL只是许多供应商使用的一种语言。请具体说明您的dbms。它被称为SQL Server,因此添加t