SQL:返回一列,其中包含具有相同值的行数

SQL:返回一列,其中包含具有相同值的行数,sql,sql-server-2008,Sql,Sql Server 2008,我有一个从数据库返回系统和区域的查询,如下所示: SELECT Areas.ID AreaID, Areas.Name AreaName, Systems.* FROM Systems INNER JOIN Areas ON Areas.ID = Systems.AreaID WHERE .... 这将返回如下所示的数据: | AreaID | AreaName | SystemName | ... | 1 | are

我有一个从数据库返回系统和区域的查询,如下所示:

SELECT  Areas.ID AreaID,
    Areas.Name AreaName,
              Systems.*

FROM Systems
INNER JOIN Areas ON Areas.ID = Systems.AreaID
WHERE ....
这将返回如下所示的数据:

|  AreaID   |  AreaName   | SystemName  | ...
|     1     |    area1    |     sys1    |
|     1     |    area1    |     sys2    |
|     1     |    area1    |     sys3    |
|     1     |    area1    |     sys4    |
|     2     |    area2    |     sys5    |
|     2     |    area2    |     sys6    |
我想返回一个额外的列,其中包含返回的每个区域中的系统数,因此我最终得到如下结果:

|  AreaID   |  AreaName   | SystemName  |  noOfSystems  | ...
|     1     |    area1    |     sys1    |       4       |
|     1     |    area1    |     sys2    |       4       |
|     1     |    area1    |     sys3    |       4       |
|     1     |    area1    |     sys4    |       4       |
|     2     |    area2    |     sys5    |       2       |
|     2     |    area2    |     sys6    |       2       |
SELECT 
  a.ID AreaID,
  a.Name AreaName,
  s1.*,
  (SELECT COUNT(s2.SystemName)
   FROM Systems s2 
   WHERE a.id = s2.AreasID) AS noofSystem
FROM Systems s1
INNER JOIN Areas a ON a.ID = S1.AreaID
WHERE ....
即,有4个系统的区域id为1,2个系统的区域id为2


如何做到这一点?我肯定听说有一个内置函数可以实现这一点,但我找不到我想要的功能。

使用如下相关子查询:

|  AreaID   |  AreaName   | SystemName  |  noOfSystems  | ...
|     1     |    area1    |     sys1    |       4       |
|     1     |    area1    |     sys2    |       4       |
|     1     |    area1    |     sys3    |       4       |
|     1     |    area1    |     sys4    |       4       |
|     2     |    area2    |     sys5    |       2       |
|     2     |    area2    |     sys6    |       2       |
SELECT 
  a.ID AreaID,
  a.Name AreaName,
  s1.*,
  (SELECT COUNT(s2.SystemName)
   FROM Systems s2 
   WHERE a.id = s2.AreasID) AS noofSystem
FROM Systems s1
INNER JOIN Areas a ON a.ID = S1.AreaID
WHERE ....
或:

SELECT  
    Areas.ID AreaID,
    Areas.Name AreaName,
    Systems.SystemName,
    COUNT(Systems.SystemName) AS noOfSystems  
FROM Systems
INNER JOIN Areas ON Areas.ID = Systems.AreaID
WHERE ...
GROUP BY 
    Areas.ID AreaID,
    Areas.Name AreaName,
    Systems.SystemName;

您需要使用聚合函数
COUNT()
,然后使用
groupby
。这可以在相关子查询中完成:

SELECT  Areas.AreaID AreaID,
    Areas.areaname AreaName,
    s1.SystemName,
    (select count(systemname) 
     from systems s2
     where s1.areaid = s2.areaid
     group by areaid) noOfSystems
FROM Systems s1
INNER JOIN Areas 
    ON Areas.AreaID = s1.AreaID
WHERE ....

或者,您可以使用加入的子查询来获取总计数:

SELECT  Areas.ID AreaID,
    Areas.Name AreaName,
    s1.SystemName,
    s2.NoOfSystems
FROM Systems s1
INNER JOIN Areas 
    ON Areas.ID = s1.AreaID
INNER JOIN
(
    select COUNT(SystemName) NoOfSystems,
        AreaID
    from systems
    group by AreaID
) s2
    on s1.AreaID= s2.AreaID
WHERE ....

此版本使用子查询获取总计数,然后将其连接回
Systems
表以返回其他列(如果需要)

或者,如果RDBMS具有此选项,则可以使用窗口功能,方法是:


请参见

这将为我们提供结果中与当前行具有相同AreaID和AreaName的行数。因为我不确定AreaName是否唯一,所以我将其包括在计数中:

;WITH cte AS (
    -- Original query
    SELECT Areas.ID AreaID,
        Areas.Name AreaName,
        Systems.SystemName
    FROM Systems
        INNER JOIN Areas ON Areas.ID = Systems.AreaID
    --WHERE...
)
SELECT AreaID,
    AreaName,
    SystemName
    -- Here's where we get the count of rows returned for each unique area
    (SELECT COUNT(*) FROM cte WHERE AreaID = c.AreaID AND AreaName = c.AreaName) AS noOfSystems
FROM cte c

以这种方式使用a将允许我们使用原始查询,而无需对其进行更改。

您使用的是哪种DBMS?神谕Postgres?@steinar我不知道你为什么删除sql server 2008标记,它注意到他们使用的数据库窗口函数(count(…)over(…)也存在于其他RDBMS中,例如Oracle查看OP的所需输出,我假设他们希望结果中的行数与当前行具有相同的AreaID和AreaName,不同的系统名。@TimLehner修复了第一个版本,并添加了所有三个查询的演示