SQL记录的复杂计数

SQL记录的复杂计数,sql,sql-server,sql-server-2008-r2,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 |

我在编写查询时遇到问题,该查询在某些条件下可以查找唯一的计数/重复项。我试图一次从一个类似于此的表中获取计数:

|-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   |
我需要的是客户的计数,如下所示:

每个客户端的总记录计数 跨客户端删除重复电子邮件的良好记录计数 删除客户内重复账号的良好记录计数 跨客户删除重复账号的良好记录计数 删除客户内空白账号的良好记录计数 其中,在总行数之后/从总行数中删除任何重复项

所以joe@code.com和bob@code.com从Jets客户端删除/不计入项目间的“善后/善后/唯一电子邮件”,因为它们存在于其他客户端上,留下1个电子邮件地址sue@code.com这是来自Jets客户端的,在其他客户端上不存在

同样对于内部客户机,对于巨人客户机,2号账户是唯一的账户号,因此我不想计算任何一条记录,不管2号账户是否在其他客户机上。请查看账户号对于自身内部的所有其他客户机是如何唯一的。然而,对于Jets客户端,在客户端中查找账号时,所有3个账号在客户端中都是唯一的,但并非在所有客户端中都是唯一的,只有空值在所有客户端中都是唯一的。因此,在3个Jet账户中,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   |

同样值得注意的是,如果我想在客户端之外添加另一个层,例如客户端中代理的计数,那么这将是在客户端上向group by添加另一个字段,我该如何处理呢

我在想一种方法是使用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'
然而,我希望能够在一个查询中返回所有计数,而不是在可能的情况下拼凑出来


提前感谢您的帮助

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

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

从多个选择中拼凑起来可能是最清晰的:

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
然后可以合并结果。您还可以从客户机列表中左键联接,以确保显示空计数

但是,您也可以非常简洁地一次完成这一切。请原谅别名过长

;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

注意,我取消了“客户中没有空白账户后的良好状态”的选项,因为我认为您可以轻松添加该选项。

Define after。请注意,ID是自动生成的这一事实并不能保证顺序,特别是在以后使用新信息更新行的情况下。最好考虑一个ID的实际值是随机的,没有内在的价值。您的标准也有点不透明-到目前为止,您尝试了什么来帮助我们了解您的目标?感谢您的回答,我已经用一个我正在尝试的示例更新了我的问题,希望以后能更好地定义
;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