SQL:返回包含具有相同值的行数的列

时间:2013-02-04 15:17:22

标签: 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     |    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       |

即。有4个系统,区域ID为1和2,区域ID为2。

如何做到这一点?我确信我听说过内置函数可以做到这一点,但我找不到我想要的东西。

3 个答案:

答案 0 :(得分:4)

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

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 ....

请参阅SQL Fiddle with Demo

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

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 ....

请参阅SQL Fiddle with Demo

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

或者,如果您的RDBMS使用Count() over()具有此选项,则可以使用窗口函数:

SELECT  Areas.ID AreaID,
    Areas.Name AreaName,
    Systems.SystemName,
    COUNT(SystemName) over(partition by Areas.ID, Areas.AreaName) as NoOfSystems
FROM Systems
INNER JOIN Areas 
    ON Areas.ID = Systems.AreaID
WHERE ....

请参阅SQL Fiddle with Demo

答案 1 :(得分:1)

使用这样的相关子查询:

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;

答案 2 :(得分:0)

这将为我们提供结果中的行数,其中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

以这种方式使用common table expression将允许我们使用原始查询而无需更改它。