将NULL更改为0时计数发生次数

时间:2014-04-05 03:57:56

标签: sql sql-server tsql

我有一个这样的表(为清晰起见省略了主键):

events:

itemId  eventType
-----------------
  100      1
  101      1
  101      2
  102      2
  102      2

还有其他事件类型,但我只关心1和2。我想找到eventType每个itemId的计数,但我还需要一种方便的方法来对结果进行数学计算。例如,我想要一个这样的输出:

itemId  ones  twos   onesPct  twosPct
-------------------------------------
 100      1    0       1.0      0.0
 101      1    1       0.5      0.5
 102      0    2       0.0      1.0

在我的实际应用中,我所执行的数学运算要比百分比复杂得多。方言是T-SQL。所以现在我有这样的查询;我对SQL并不是那么出色,所以我想出的最好的是:

SELECT
  COALESCE(onest.itemId,twost.itemId) itemId,
  COALESCE(onest.n,0) ones,
  COALESCE(twost.n,0) twos,
  1.0*COALESCE(onest.n,0) / (COALESCE(onest.n,0) + COALESCE(twost.n,0)) onesPct,
  1.0*COALESCE(twost.n,0) / (COALESCE(onest.n,0) + COALESCE(twost.n,0)) twosPct
FROM
   (SELECT itemId, COUNT(*) n
    FROM events
    WHERE eventType = 1
    GROUP BY itemId) onest
FULL OUTER JOIN
   (SELECT itemId, COUNT(*) n
    FROM events
    WHERE eventType = 2 
    GROUP BY itemId) twost
ON onest.itemId = twost.itemId

这是有效的,除了方程中的所有COALESCE变得非常笨重。所以我有两个问题:

  1. 最重要的是:有没有办法在更全局的层面上将NULL从外部联接转换为0,这样我就不必继续写到处都是COALESCE(onest.n,0)?从我到目前为止看到的情况来看,我不允许在其他列规范中使用列别名,所以我不能简单地做到例如上述查询中的(1.0 * ones / (ones + twos)) onestPct(除非有办法执行此操作)?

  2. 是否有更短的查询可以完成这一切?这看起来像是一堆子查询。

  3. 我不太关心性能,主要任务是数据挖掘和分析。

    Here it is on SQLFiddle

    此外,对于糟糕的头衔道歉,我无法提出一个很好的简短摘要。

3 个答案:

答案 0 :(得分:3)

我知道你说你所做的事情比百分比更复杂,但我认为无论关键只是一个子查询。

首先进行分组工作。完成后,将其用作查询的源,您可以在其中进行实际数学运算。当然,如果它过于复杂,您可以考虑将该子查询放入临时表中。

所以如果只是你提供的数据,我会这样做。

select itemid,
       ones,
       twos,
       ones + twos as total,
       100 * (round(ones / (ones + twos), 4)) as ones_perc,
       100 * (round(twos / (ones + twos), 4)) as twos_perc
from 
    (select itemid,
       sum(case when eventtype = 1 then 1 else 0 end) as ones,
       sum(case when eventtype = 2 then 1 else 0 end) as twos
     from a
     group by itemid)b

答案 1 :(得分:1)

您可以在SUM()上使用汇总函数(CASE),从而简化整个查询:

select itemId,
  sum(case eventType when 1 then 1 else 0 end) ones,
  sum(case eventType when 2 then 1 else 0 end) twos,
  convert(float, sum(case eventType when 1 then 1 else 0 end)) / count(eventType) onesPct,
  convert(float, sum(case eventType when 2 then 1 else 0 end)) / count(eventType) twosPct
from events
group by itemId

SQL Fiddle Demo

如果有些项目没有任何事件,您应该排除它们或单独处理百分比计算,因为上面的查询将导致除以零。

答案 2 :(得分:1)

select itemId,ones,twos,ones/c onesPct,twos/c twosPct from (
 select itemId,sum(2-eventType) ones,sum(eventType-1) twos,sum(1.0) c from events where eventType in (1,2) group by itemId
) e