Правильно ли использовать Count () и Sum () в SQL? - PullRequest
4 голосов
/ 28 октября 2011

Хорошо, я надеюсь, что смогу объяснить этот вопрос достаточно хорошо, потому что чувствую, что это будет непросто.

У меня есть две таблицы, с которыми я сегодня работаю. Это выглядит так:

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

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

В первой таблице хранятся записи, которые говорят мне, о, у этого человека есть эта система, которая состоит из этих прав, у которых есть эти цели. Немного сложно, но оставайся со мной. Второй хранит TargetName, а затем указывает, есть ли у этой цели разъем в моей не теоретической системе.

Я пытаюсь объединить эти две таблицы, чтобы я мог видеть флаг цели для каждой строки в @pset. Это поможет мне позже, как вы увидите.

Если у каждого права в системе есть соединитель с целью (флаг для всех из них равен true ), я бы хотел знать.

Все остальные должны пойти в другой стол.

Это то, что я пытался сделать, но это не сработало. Мне нужно знать, где я ошибся. Надеюсь, кто-то с большим опытом, чем я, сможет ответить.

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

2 голосов
/ 28 октября 2011

Ваша основная проблема в том, что вы пытаетесь свернуть до двух разных наборов записей.
В начальном наборе (предложения SELECT и GROUP BY) говорится, что вы хотите одну запись для каждого различия в наборе [ProfileId, SystemId, EntitlementId, TargetId, fConnector].
Второй набор (предложение HAVING) говорит, что вы хотите, чтобы каждая строка в начальном наборе сравнивала COUNT записей с SUM соединений. Однако, поскольку вы попросили сгруппировать по отдельному флагу, это приводит к получению одной строки для каждого флага (при условии отношений 1-к-1). По сути, вы говорите: «Эй, если у этой цели есть связь? Да, я хочу это ».

То, что вы видите хотите - это свертывание до значения SystemId. Для этого вам нужно изменить предложения SELECT и GROUP BY, чтобы они включали только набор [ProfileId, SystemId]. Это вернет только те строки (введенные из профиля и системы), у которых все цели «подключены». Вы не сможете увидеть отдельные права, цели и то, связаны ли они (однако вы сможете сделать вывод , что все они будут / не будут подключены, однако).

<Ч />

РЕДАКТИРОВАТЬ:

В целях полного раскрытия, вот как вы получите что-то похожее на исходный набор результатов, где перечислены все EntitlementId с и TargetId с:

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, ключей ProfileId / SystemRoleId, где все EntitlementId s и TargetId s имеют соединение (или переверните CTE = на <> для тех, где не все так делают).

1 голос
/ 28 октября 2011

Редактировать: исправил мои исходные запросы, также обновил описание

Вы можете разделить это: сначала найдите TargetID с fConnector 0. Затемнайдите пары PersonID, SystemID, у которых любая цель равна тем, которые вы нашли.Затем выберите соответствующие данные: (это находит пару PersonID, SystemID, где хотя бы одно право не имеет соединителя с целью)

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

Запрос для поиска PersonID,SystemID пар, где все права имеют соединитель с целью, аналогичны:

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

Разница заключается в объединении с временной таблицей (<> против =).Это очень похоже на ответ нуля, но не использует счет или сумму.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...