SQL记录的复杂计数

时间:2014-03-30 00:07:17

标签: sql sql-server sql-server-2008-r2

我遇到了编写查询的问题,该查询可以在特定条件下查找唯一计数/重复项。我试图从一个类似于这个的表中一次得到计数:

|-P_key-|-----email-----|-act_no-|--Client--|
|   1   | joe@code.com  |    1   |   Jets   |
|   2   | bob@code.com  |    2   |   Jets   |
|   3   | sue@code.com  |  NULL  |   Jets   |
|   4   | joe@code.com  |    1   |   Bills  |
|   5   | bob@code.com  |    2   |   Bills  |
|   6   | bob@code.com  |    2   |   Giants |
|   7   | max@code.com  |    2   |   Giants |
|   8   | ben@code.com  |    5   |   Pats   |

我需要的是客户的计数如下:

  1. 每个客户的总记录数
  2. 删除了客户端重复电子邮件的良好记录数
  3. 在客户移除
  4. 内重复帐户号的良好记录数
  5. 已移除客户的重复帐户号
  6. 的良好记录数
  7. 已移除客户端中空白帐户号的良好记录数
  8. 从总行数开始/之后删除任何重复项。

    因此,来自Jets客户端的joe@code.com和bob@code.com被删除/不计入好/之后/来自项目中的独特电子邮件,因为它们存在于其他客户端上,留下1个电子邮件地址( sue@code.com)来自Jets客户端,在其他客户端上不存在。

    对于内部客户端,对于Giants客户端,acct_no 2是唯一的acct_no,所以我不想计算任何一条记录,无论acct_no 2是否在其他客户端上(请参阅acct_no对于其他所有客户端的唯一性)客户内部)。而在跨客户端查找acct_nos时,对于Jets客户端,所有3个acct_no在客户端中都是唯一的,但不是在所有客户端上(只有空值在所有客户端中是唯一的)。因此,在3台喷气机中,3台在客户中很好,但在客户中只有1台是好的。

    我希望实现的输出结果如下(尽管最终数据并不一定需要如此转动):

     |                                             |  Jets  |  Bills | Giants |  Pats |
     | Total emails                                |   3    |    2   |    2   |   1   |
     | good after unique emails across clients     |   1    |    0   |    1   |   1   |
     | good after unique account_no across clients |   1    |    0   |    0   |   1   |
     | good after unique account_no within clients |   3    |    2   |    0   |   1   |
     | good after blank account_no within clients  |   2    |    0   |    0   |   0   |
    

    OR

     |        |  tot unique emails |  good emails        | etc...
     | Jets   |   3                |    1                |   
     |Bills   |   2                |    0                |   
     | Giants |   2                |    1                |    
     | Pats   |   1                |    1                |   
    

    另外值得注意的是,如果我想添加另一个层而不是客户端,例如客户端中代理的计数,那么它将在客户端上向该组添加另一个字段,我该如何处理它?<​​/ p>

    我在想一种方法是使用where not exists语句,例如:

     SELECT COUNT(x.act_no)
     FROM x
     WHERE NOT EXISTS (SELECT 'x' FROM t WHERE t.act_no = x.act_no)
     AND x.client = 'Jets'
    

    但是,我希望能够在一个查询中返回所有计数,而不是在可能的情况下将其拼凑出来。

    提前感谢您提供任何帮助!

2 个答案:

答案 0 :(得分:0)

不完全确定我是否正确地解释了聚合规则,但这就是我想出的。这是一个垂直结果,如果你希望它是水平的,你可以转动它。

SELECT  Client, result, CountType
    FROM    (SELECT        Client, COUNT(*) AS result, 'Total emails' AS CountType
                FROM            ComplexCounting
                GROUP BY Client
                UNION
                SELECT        Client, COUNT(*) AS result, 'good after unique emails across clients' AS CountType
                FROM            ComplexCounting
                WHERE        (NOT EXISTS
                                            (SELECT        Id, email, act_no, Client
                                                FROM            ComplexCounting AS c
                                                WHERE        (Client <> ComplexCounting.Client) AND (email = ComplexCounting.email)))
                GROUP BY Client
                UNION
                SELECT        Client, COUNT(*) AS result, 'good after unique account_no across clients' AS CountType
                FROM            ComplexCounting
                WHERE        (NOT EXISTS
                                            (SELECT        Id, email, act_no, Client
                                                FROM            ComplexCounting AS c
                                                WHERE        (Client <> ComplexCounting.Client) AND (act_no = ComplexCounting.act_no)))
                GROUP BY Client
                UNION
                SELECT        Client, COUNT(*) AS result, 'good after unique account_no within clients' AS CountType
                FROM            ComplexCounting
                WHERE        (NOT EXISTS
                                            (SELECT        Id, email, act_no, Client
                                                FROM            ComplexCounting AS c
                                                WHERE        (Client = ComplexCounting.Client) AND (act_no = ComplexCounting.act_no) AND (Id <> ComplexCounting.Id)))
                GROUP BY Client
                UNION
                SELECT        Client, COUNT(DISTINCT act_no) AS result, 'good after blank account_no within clients' AS CountType
                FROM            ComplexCounting
                WHERE        EXISTS
                                            (SELECT        Id, email, act_no, Client
                                                FROM            ComplexCounting AS c
                                                WHERE        (act_no IS NULL) AND (Client = ComplexCounting.Client)) AND (act_no IS NOT NULL)
                GROUP BY Client) AS Results
    ORDER BY CountType

答案 1 :(得分:0)

从多个选项中将它拼凑起来可能是最清楚的:

DECLARE @tbl TABLE (id INT, email VARCHAR(256), act_no INT NULL, client VARCHAR(10))
INSERT INTO @tbl VALUES
 (   1   , 'joe@code.com'  ,    1   ,   'Jets'   )
,(   2   , 'bob@code.com'  ,    2   ,   'Jets'   )
,(   3   , 'sue@code.com'  ,  NULL  ,   'Jets'   )
,(   4   , 'joe@code.com'  ,    1   ,   'Bills'  )
,(   5   , 'bob@code.com'  ,    2   ,   'Bills'  )
,(   6   , 'bob@code.com'  ,    2   ,   'Giants' )
,(   7   , 'max@code.com'  ,    2   ,   'Giants' )
,(   8   , 'ben@code.com'  ,    5   ,   'Pats'   )     

SELECT 'Total emails',client, COUNT(*)
  FROM @tbl 
 GROUP BY client

SELECT 'good after unique emails across clients',client, COUNT(*)
  FROM @tbl a
 WHERE NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.email=a.email AND b.client <> a.client)
 GROUP BY client

SELECT 'good after unique account_no across clients',client, COUNT(*)
  FROM @tbl a
 WHERE NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.act_no=a.act_no AND b.client <> a.client)
 GROUP BY client

SELECT 'good after unique account_no within clients',client, COUNT(*)
  FROM @tbl a
 WHERE NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.act_no=a.act_no AND b.client = a.client GROUP BY b.act_no,b.client HAVING COUNT(*) > 1)
 GROUP BY client

然后你可以UNION结果。您还可以从客户列表中LEFT JOIN以确保显示空计数。

但是,您也可以相当简洁地一次完成所有操作。请原谅过长的别名。

;WITH cte AS (
       SELECT client
             ,CASE WHEN NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.email=a.email AND b.client <> a.client) THEN 1 ELSE 0 END [good after unique emails across clients]
             ,CASE WHEN NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.act_no=a.act_no AND b.client <> a.client) THEN 1 ELSE 0 END [good after unique account_no across clients]
             ,CASE WHEN NOT EXISTS (SELECT 1 FROM @tbl b WHERE b.act_no=a.act_no AND b.client = a.client GROUP BY b.act_no,b.client HAVING COUNT(*) > 1) THEN 1 ELSE 0 END [good after unique account_no within clients]
         FROM @tbl a
     )
     SELECT client
           ,COUNT(*) [Total emails]
           ,SUM([good after unique emails across clients]) [good after unique emails across clients]
           ,SUM([good after unique account_no across clients]) [good after unique account_no across clients]
           ,SUM([good after unique account_no within clients]) [good after unique account_no within clients]
      FROM cte a
     GROUP BY client

注意,我在客户的空白account_no之后离开了&#39;因为我认为你可以很容易地添加它。