根据存在条件计算行数

时间:2017-07-07 17:54:27

标签: sql sql-server tsql count aggregate-functions

我研究了许多Stackoverflow问题,演示了如何使用CASE语句向COUNT语句添加条件,但我找不到如何做我需要的示例。我们假设我有以下表格:

CREATE TABLE [Project](
    [ProjectId] [int] NOT NULL,
    [ProjectName] [nvarchar](100) NOT NULL
)
GO

CREATE TABLE [ProjectTask](
    [ProjectTaskId] [int] NOT NULL,
    [ProjectId] [int] NOT NULL,
    [TaskName] [nvarchar](100) NOT NULL
)
GO

CREATE TABLE [ProjectTaskOwner](
    [ProjectTaskId] [int] NOT NULL,
    [UserId] [int] NOT NULL
 )
GO

CREATE TABLE [ProjectTaskEntity](
    [ProjectTaskId] [int] NOT NULL,
    [EntityId] [int] NOT NULL,
    [AssignedUserId] [int]
 )
GO

INSERT Project (ProjectId, ProjectName) VALUES (1, 'Test Project')
INSERT ProjectTask (ProjectTaskId, ProjectId, TaskName) VALUES(1, 1, 'Task1')
INSERT ProjectTask (ProjectTaskId, ProjectId, TaskName) VALUES(2, 1, 'Task2')
INSERT ProjectTaskOwner (ProjectTaskId, UserId) VALUES (1, 1)
INSERT ProjectTaskOwner (ProjectTaskId, UserId) VALUES (1, 2)
INSERT ProjectTaskOwner (ProjectTaskId, UserId) VALUES (1, 3)
INSERT ProjectTaskEntity (ProjectTaskId, EntityId, AssignedUserId) VALUES (1, 1, 1)
INSERT ProjectTaskEntity (ProjectTaskId, EntityId, AssignedUserId) VALUES (1, 2, 2)
INSERT ProjectTaskEntity (ProjectTaskId, EntityId, AssignedUserId) VALUES (1, 3, 3)
INSERT ProjectTaskEntity (ProjectTaskId, EntityId, AssignedUserId) VALUES (1, 4, 256)

我想要做的是为每个项目任务获取分配给我并分配给其他任务所有者的实体的数量。因此,对于上面的测试数据,如果用户ID为1且项目ID为1,我期望:

| TaskId | AssignedToMe | AssignedToOthers |
|   1    |      1       |       2          |
|   2    |      0       |       0          |

所以这就是我到目前为止:

DECLARE @userId INT = 1   
SELECT 
    pt.ProjectId,
    pt.ProjectTaskId,
    COUNT(CASE WHEN pte.AssignedUserId = @userId THEN 1 ELSE NULL END) AS AssignedTo
FROM ProjectTask pt
INNER JOIN Project p
    ON p.ProjectId = pt.ProjectId
LEFT JOIN ProjectTaskEntity pte
    ON pte.ProjectTaskId = pt.ProjectTaskId
WHERE p.ProjectId = 1
GROUP BY pt.ProjectId,  pt.ProjectTaskId

分配给我很容易。问题是我不确定如何做别人,因为别人不只是不是我的人。此任务中没有任何人不在ProjectTaskOwner表中。任何人都知道如何实现这个目标?

6 个答案:

答案 0 :(得分:2)

我不明白为什么你需要为此项目表。我会把它写成:

SELECT pt.ProjectId, pt.ProjectTaskId,
       SUM(CASE WHEN pte.AssignedUserId = @userId THEN 1 ELSE 0 END) AS AssignedToMe,
       SUM(CASE WHEN pto.UserId IS NULL THEN 1 ELSE 0 END) AS AssignedToOthers
FROM ProjectTask pt LEFT JOIN
     ProjectTaskEntity pte
     ON pte.ProjectTaskId = pt.ProjectTaskId LEFT JOIN
     ProjectTaskOwner pto
     ON pto.ProjectTaskId = pt.ProjectTaskId AND
        pto.UserId = pte.AssignedUserId
WHERE pt.ProjectId = 1
GROUP BY pt.ProjectId, pt.ProjectTaskId;

我将COUNT()替换为SUM()。作为优先选择,在这种情况下我更喜欢SUM()

答案 1 :(得分:1)

这是解决我问题的实际查询。有几个帖子帮助我找到了这个,所以感谢大家的答案:

DECLARE @userId INT = 1   
SELECT 
    pt.ProjectId,
    pt.ProjectTaskId,
    COUNT(CASE WHEN pte.AssignedUserId = @userId THEN 1 ELSE NULL END) AS AssignedTo,
    COUNT(CASE WHEN eao.OtherUser IS NULL THEN NULL ELSE 1 END) AS AssignedToOther
FROM ProjectTask pt
LEFT JOIN ProjectTaskEntity pte
    ON pte.ProjectTaskId = pt.ProjectTaskId
LEFT JOIN (
    SELECT sPto.ProjectTaskId, sPto.UserId as OtherUser
    FROM ProjectTaskOwner sPto
    WHERE sPto.UserId <> @userId
) eao
    ON  pt.ProjectTaskId = eao.ProjectTaskId AND pte.AssignedUserId = eao.OtherUser
WHERE pt.ProjectId = 1
GROUP BY pt.ProjectId,  pt.ProjectTaskId

答案 2 :(得分:0)

就像做相反的事情一样简单

DECLARE @userId INT = 1   
SELECT 
    pt.ProjectId,
    pt.ProjectTaskId,
    COUNT(CASE WHEN pte.AssignedUserId = @userId THEN 1 ELSE NULL END) AS AssignedToMe,
    COUNT(CASE WHEN pte.AssignedUserId = @userId THEN null ELSE 0 END) AS AssignedToOthers

FROM ProjectTask pt
INNER JOIN Project p
    ON p.ProjectId = pt.ProjectId
LEFT JOIN ProjectTaskEntity pte
    ON pte.ProjectTaskId = pt.ProjectTaskId
WHERE p.ProjectId = 1
GROUP BY pt.ProjectId,  pt.ProjectTaskId

答案 3 :(得分:0)

使用SUM代替COUNT

DECLARE @userId INT = 1   
SELECT pt.ProjectTaskId,
    ISNULL(SUM(CASE WHEN pte.AssignedUserId = @userId THEN 1 END),0) AS AssignedToMe,
    ISNULL(SUM(CASE WHEN pte.AssignedUserId <> @userId THEN 1 END),0) AS AssignedToOthers
FROM ProjectTask pt
INNER JOIN Project p ON p.ProjectId = pt.ProjectId
LEFT JOIN ProjectTaskEntity pte ON pte.ProjectTaskId = pt.ProjectTaskId
WHERE p.ProjectId = 1
GROUP BY  pt.ProjectTaskId

根据您提供的数据,结果如下:

ProjectTaskId   AssignedToMe    AssignedToOthers
1               1               3
2               0               0

请参阅SQL Fiddle中的结果。

答案 4 :(得分:0)

我认为这解决了这个问题。 您将计算其他人,而不是您和未在ProjectTaskOwner表中执行此任务的任何人。

DECLARE @userId INT = 1   
SELECT 
    pt.ProjectId,
    pt.ProjectTaskId,
    COUNT(CASE WHEN pte.AssignedUserId = @userId THEN 1 ELSE NULL END) AS AssignedTo,
    COUNT(CASE WHEN pte.AssignedUserId != @userId AND pte.AssignedUserId != pto.UserId THEN 1 ELSE NULL END) AS AssignedTo
FROM ProjectTask pt
INNER JOIN Project p
    ON p.ProjectId = pt.ProjectId
LEFT JOIN ProjectTaskEntity pte
    ON pte.ProjectTaskId = pt.ProjectTaskId
LEFT JOIN ProjectTaskOwner pto
    on pto.ProjectTaskId = pt.ProjectTaskId
WHERE p.ProjectId = 1
GROUP BY pt.ProjectId,  pt.ProjectTaskId

答案 5 :(得分:0)

DECLARE @userId INT = 1   
SELECT 
    pt.ProjectId,
    pt.ProjectTaskId,
    ISNULL(SUM(CASE WHEN pte.AssignedUserId = @userId THEN 1 END),0) AS AssignedToMe,
    ISNULL(SUM(CASE WHEN pte.AssignedUserId <> @userId THEN 1 END),0) AS AssignedToOthers
FROM ProjectTask pt
INNER JOIN Project p
    ON p.ProjectId = pt.ProjectId
LEFT JOIN ProjectTaskOwner pto
    ON pto.ProjectTaskId = pt.ProjectTaskId
LEFT JOIN ProjectTaskEntity pte
    ON pte.ProjectTaskId = pt.ProjectTaskId and
    pte.AssignedUserId = pto.UserId
WHERE p.ProjectId = 1
GROUP BY pt.ProjectId,  pt.ProjectTaskId

http://www.sqlfiddle.com/#!6/58f1e4/28