0

我有一张桌子,上面有来自不同用户的订单。每个用户(由电子邮件地址标识)可以有任意数量的订单。我没有额外的用户表,只有一个普通的 OrderData 表。我想要的听起来很简单:

  1. 用户总数
  2. XYZ 用户数
  3. 非 XYZ 用户数

其中 1. 是 2. 和 3. 的总和。“XYZ”用户由以“@xyz.com”结尾的电子邮件地址定义。

我想要一个查询,在三列中返回三个值。我目前拥有的是:

SELECT 
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [Total Users],
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND User_EmailAddress LIKE '%@xyz.com'
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [XYZUsers],
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND User_EmailAddress NOT LIKE '%@xyz.com'
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [Non-XYZ Users]

它返回正确的结果集:

Total Users | XYZ Users | Non-XYZ Users
------------+-----------+--------------
        123 |        23 |           100

有没有更好的方法来编写这个查询,而不是基本上使用相同的代码进行三个类似的查询?

4

2 回答 2

2

这是一种减少冗余代码并避免多次扫描数据问题的解决方案。由于您真正关心的是计数,因此您甚至不需要返回任何实际数据,并且您可以将几乎所有逻辑折叠成一个CASE表达式:

;WITH x AS 
(
  SELECT isxyz = CASE WHEN User_EmailAddress LIKE '%@xyz.com' THEN 1 ELSE 0 END
  FROM dbo.OrderData
  WHERE User_EmailAddress IS NOT NULL
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    GROUP BY User_EmailAddress
)
SELECT 
  TotalUsers      = COUNT(isxyz),
  XYZUsers        = SUM(isxyz),
  [Non-XYZ Users] = COUNT(NULLIF(isxyz,1))
FROM x;

诀窍是利用聚合对您有利。由于1/0输出不是真正的BIT列,因此您可以SUM获取1s 的计数。而相反的情况可以通过将1s更改为 来实现NULL,因为NULLs 会被 忽略COUNT

于 2013-04-12T16:16:14.300 回答
0

bluefeet 提供的解决方案仍然有一个缺点——每个 DISTINCT 聚合(在本例中为 COUNT)分别使用输入行流。这可能会导致对基表进行单独的扫描/查找 - 每个不同的聚合一组。尽管有时优化器可以将基表搜索/扫描假脱机到工作表中,然后计算聚合。

一种更注重性能的方法(在这种特定情况下)是将总计数放入一个变量,然后将 xyz 计数放入另一个变量,然后使用标量算术推导出第三个值(非 xyz)。这样你就可以避免一个假脱机重播(或者更糟糕的是基表查找/扫描运算符。)

阅读 Paul White 的博客了解更多信息:http ://web.archive.org/web/20170606142356/http://sqlblog.com/blogs/paul_white/archive/2011/12/04/is-distinct-aggregation-仍然认为有害的.aspx

于 2013-04-12T16:24:56.197 回答