【问题标题】:Join query results with different WHERE conditions加入不同 WHERE 条件的查询结果
【发布时间】:2013-06-05 18:12:53
【问题描述】:

是否可以将这两个查询合并为一个?现在,我运行了 2 个单独的查询来显示:

  1. 用户名以及他们打开了多少个问题
  2. 用户名以及他们关闭了多少问题

未决问题:

SELECT FirstName +' ' + LastName AS 'UserName', COUNT(u.UserID) AS IssuesOpened
FROM Users u
LEFT OUTER JOIN Issues i ON i.CreatedByUserID = u.UserID
WHERE i.DateCreated BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01'
GROUP BY LastName, FirstName

结果如下所示:

UserName | IssuesOpened
-----------------------
User 1      10
User 2      8
User 3      55

已解决的问题:

SELECT FirstName +' ' + LastName AS 'UserName', COUNT(u.UserID) AS IssuesClosed
FROM Users u
LEFT OUTER JOIN Issues i ON i.ResolvedByUserID = u.UserID
WHERE ResolvedDate BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01'
GROUP BY LastName, FirstName

结果如下所示:

UserName | IssuesClosed
-----------------------
User 1      8
User 2      2
User 3      40

我想加入这两个查询来得到这个:

UserName | IssuesOpened | IssuesClosed
--------------------------------------
User 1      10              8
User 2      8               2
User 3      55              40

我尝试了一些丑陋的东西,像这样:

SELECT FirstName + ' ' + LastName AS UserName,
    (SELECT COUNT(u.UserID)
    FROM Users u
    LEFT OUTER JOIN Issues i ON i.ResolvedByUserID = u.UserID
    WHERE ResolvedDate BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01')
    AS IssuesClosed,
    (SELECT COUNT(u.UserID)
        FROM Users u
        LEFT OUTER JOIN Issues i ON i.CreatedByUserID = u.UserID
        WHERE i.DateCreated BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01')
    AS IssuesOpened
FROM Users u
GROUP BY FirstName, LastName

但是因为我在每个子查询中删除了GROUP BY 子句,所以它只返回总行数。

更新

由于我无法将数据加载到 SqlFiddle 中(查询窗口和架构窗口都只能容纳 8000 个字符),我想出了一些我的结果与 sgeddes 结果的屏幕截图:

我的结果 PhotoBucket Link to larger image:

sgeddes 结果

让我印象深刻的一件事是,如果您注意到 sgeddes 结果,最后一行用户“Web***”的“已关闭”为 449。这是不可能的,因为该用户 (Web***) 是我们如何确定客户如何通过我们的网站打开问题的占位符。此假用户无权访问我们的系统,也无法关闭任何工单。

【问题讨论】:

    标签: sql sql-server-2008-r2


    【解决方案1】:

    这应该可以使用COUNTCASE

    SELECT FirstName +' ' + LastName AS 'UserName', 
        COUNT(CASE WHEN i.DateCreated BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01' 
                   THEN 1 END) AS IssuesOpened, 
        COUNT(CASE WHEN ResolvedDate BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01' 
                   THEN 1 END) AS IssuesClosed
    FROM Users u
        LEFT OUTER JOIN Issues i ON i.CreatedByUserID = u.UserID OR i.ResolvedByUserID = u.UserID
    GROUP BY LastName, FirstName
    

    这将返回所有用户 - 因此有些用户的计数可能为 0。如果您不想要所有用户,您可以使用 ORGROUP BY 上方添加您的 WHERE 条件。在这样做时,您否定了需要OUTER JOIN 的原因,所以我会将其更改为INNER JOIN

    SELECT FirstName +' ' + LastName AS 'UserName', 
        COUNT(CASE WHEN i.DateCreated BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01' 
               THEN 1 END) AS IssuesOpened, 
        COUNT(CASE WHEN ResolvedDate BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01' 
               THEN 1 END) AS IssuesClosed
    FROM Users u
        INNER JOIN Issues i ON 
             i.CreatedByUserID = u.UserID OR i.ResolvedByUserID = u.UserID
    WHERE i.DateCreated BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01'
        OR ResolvedDate BETWEEN '06/30/2012 23:59:59' AND '07/01/2013 00:00:01'
    GROUP BY LastName, FirstName
    

    顺便说一句——在处理日期字段时,我建议相应地使用 >= 和 BETWEEN。

    【讨论】:

    • 你为什么不喜欢 BETWEEN?
    • @Goat_CO -- 看看这篇文章有几个很好的理由:sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/…
    • 哦,您的意思是在处理 DATETIME 字段时,而不是 DATE 字段。我不会被那篇文章所强迫,如果我们仅限于使用不会让某些人感到困惑的功能,我们将不会使用太多东西。
    • @sgeddes 在运行您最新的第二个查询时,我得到的用户值与单独运行查询不同。例如,对于用户“Andrew”,您的查询返回 317 打开和 347 关闭,但是当我运行单个查询时,我得到 147 打开和 291 关闭。我会尝试让 SQLFiddle 看看是否有帮助。
    • @Robert -- 小提琴好运吗?除非我遗漏了什么,否则这看起来应该可以工作。
    【解决方案2】:

    我会这样处理:

    1. 取消透视指定时间段内的所有 Issue 数据,以便每一行仅包含用户 ID 和用户引起的状态更改('Opened''Closed')。

    2. 透视结果集,计算每个用户 ID 的状态变化。

    3. 将透视集加入Users 以访问名称。

    这是我在实现上述过程中想到的:

    WITH unpivoted AS (
      SELECT
        x.UserID,
        x.IssueStatusChange
      FROM Issues
      CROSS APPLY (
        VALUES
          (CreatedByUserID,  'Opened', DateCreated),
          (ResolvedByUserID, 'Closed', ResolvedDate)
      ) x (UserID, IssueStatusChange, ChangeDate)
      WHERE x.ChangeDate BETWEEN '06/30/2012 23:59:59'
                             AND '07/01/2013 00:00:01'
    ),
    pivoted AS (
      SELECT
        UserID,
        Opened,
        Closed
      FROM unpivoted
      PIVOT (COUNT(IssueStatusChange)
      FOR IssueStatusChange IN (Opened, Closed)) p
    ),
    SELECT
      UserName = u.FirstName + ' ' + u.LastName,
      p.Opened,
      p.Closed
    FROM Users u
    INNER JOIN pivoted p ON u.UserID = p.UserID
    ;
    

    如果有人对此感兴趣,还有一个 SQL Fiddle demo 用于此查询,尽管测试数据集不是很出色(不过可能还可以看到正在工作的东西)。

    【讨论】:

      猜你喜欢
      • 2020-01-06
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 2019-10-22
      • 2015-12-17
      相关资源
      最近更新 更多