在SQL中正确使用Count()和Sum()?

时间:2011-10-28 14:37:02

标签: sql sql-server tsql count sum

好的,所以我希望我能够很好地解释这个问题,因为我觉得这将是一个艰难的问题。

我今天有两张桌子。这些看起来像:

@pset table (PersonID int, SystemID int, EntitlementID int, TargetID int)

@Connector table (TargetName varchar(10), fConnector bit)

第一个表存储了告诉我的记录,哦,这个人有这个系统,由这些权利组成,他们有这些目标。有点复杂,但留在我身边。第二个存储TargetName,然后存储该目标是否在我不太理论的系统中具有连接器。

我要做的是合并这两个表,以便我可以在@pset中看到每一行的目标标志。这将有助于我后来,你会看到。

如果系统中的每个权利都有一个到目标的连接器(标志为真,对于所有这些),那么我想知道。

所有其他人应该进入另一张桌子。

这是我试图做的,但它不起作用。我需要知道我哪里出错了。希望有比我更多经验的人能够回答。

-- If the count(123) = 10 (ten rows with SystemID = 123) and the sum = 10, cool.
select pset.*, conn.fConnector from @pset pset
inner join vuTargets vt
on vt.TargetID = pset.TargetID
inner join @conn conn
on  conn.TargetName = vt.TargetName
group by ProfileID, SystemRoleID, EntitlementID, TargetID, fConnector
having count(SystemID) = sum(cast(fConnector as int))
order by ProfileID

-- If the count(123) = 10 (ten rows with SystemID = 123) and the sum <> 10
select pset.*, conn.fConnector from @pset pset
inner join vuTargets vt
on vt.TargetID = pset.TargetID
inner join @conn conn
on  conn.TargetName = vt.TargetName
group by ProfileID, SystemRoleID, EntitlementID, TargetID, fConnector
having count(SystemID) <> sum(cast(fConnector as int))
order by ProfileID

不幸的是,这些不起作用:(

修改

enter image description here

以下是显示问题的屏幕截图。注意ProfileID 1599的SystemID为1126567,但其中一个权利没有连接器!如何将这两行都放入第二个查询? (上图)

2 个答案:

答案 0 :(得分:2)

您的基本问题是您正在尝试累积到两个不同的记录集 初始集(SELECTGROUP BY子句)表示您希望集合[ProfileId,SystemId,EntitlementId,TargetId,fConnector]中的每个差异都有一条记录。
第二组(HAVING子句)表示您希望 inital set 中的每一行都将COUNT个记录与SUM进行比较的联系。但是,因为您已经要求分组到单个标志,这会为每个标志获取单行(假设为1对1关系) 。实际上,你说 - '嘿,如果这个目标有连接?是的,我想要它。

您希望想要的内容是SystemId值。为此,您需要将SELECTGROUP BY子句更改为仅包含[ProfileId,SystemId]集。这将仅返回所有目标“已连接”的行(从配置文件和系统键入)。您能够看到各个权利,目标以及它们是否已连接(您将能够推断它们将全部/不连接,但是)。


编辑:

为了充分披露,以下是您如何获得与原始结果集类似的内容,其中列出了所有EntitlementIdTargetId s:

WITH all_connections as (SELECT pset.ProfileId, pset.SystemRoleId
                         FROM @pset pset
                         INNER JOIN vuTargets vt
                         ON vt.TargetId = pset.TargetId
                         INNER JOIN @conn conn
                         ON conn.TargetName = vt.TargetName
                         GROUP BY pset.ProfileId, pset.SystemRoleId
                         HAVING COUNT(pset.SystemRoleId) 
                                                  = SUM(CAST(fConnector as INT)))

SELECT pset.*
FROM @pset pset
JOIN all_connections conn
ON conn.ProfileId = pset.ProfileId
AND conn.SystemRoleId = pset.SystemRoleId

这会为您提供TargetId / ProfileIdSystemRoleId个列表的列表,其中所有EntitlementIdTargetId都有连接(或者,将CTE =翻转为<>,以便那些不是全部的人。{/ p>

答案 1 :(得分:1)

编辑修复了原始查询,同时更新了说明

您可以拆分:首先找到TargetID为0的fConnector。然后找到任意目标等于的PersonIDSystemID对你找到的那些。然后选择相关数据:(这会找到PersonIDSystemID对,其中至少有一个权利没有到目标的连接器)

with abc as (
    select PersonID, SystemID
    from pset P
    where TargetID in (
        select TargetID
        from vuTargets V join connector C on V.TargetName = C.TargetName
        where C.fConnector = 0
        )
)
select P.PersonID, P.SystemID, P.EntitlementID, P.TargetID, C.fConnector
from pset P
    join abc on ((P.PersonID = abc.PersonID) and (P.SystemID = abc.SystemID))
    join vuTargets V on P.TargetID = V.TargetID
    join connector C on V.TargetName = C.TargetName

查找PersonIDSystemID对的查询,其中所有权利都具有到目标的连接器类似:

with abc as (
    select PersonID, SystemID
    from pset P
    where TargetID in (
        select TargetID
        from vuTargets V join connector C on V.TargetName = C.TargetName
        where C.fConnector = 0
        )
)
select P.PersonID, P.SystemID, P.EntitlementID, P.TargetID, C.fConnector
from 
    pset P
    join abc on ((P.PersonID <> abc.PersonID) or (P.SystemID <> abc.SystemID))
    join vuTargets V on P.TargetID = V.TargetID
    join connector C on V.TargetName = C.TargetName

区别在于与临时表的联接(<> vs =)。这与零的答案非常相似,但不使用计数或总和。