0

我有下表

id  rid     eId     vs  isN
24  3   22  2   1
25  3   21  2   1
26  60  21  2   1
27  60  21  2   1
28  60  21  2   1
29  60  21  2   1
30  60  21  2   1
31  60  21  2   1
32  81  21  2   1
35  60  22  2   1
36  81  22  2   1
37  0   22  2   1
38  60  22  2   1
39  81  22  2   1
40  0   22  2   1
41  60  22  2   1
42  81  22  2   1
43  3   22  2   1

eId我有 8 个不同的数字上,我想计算这八个不同的 eid,甚至算作“0”我想要得到的是一个包含 8 个值的数组,键应该是八个不同的名称。"vs" 是 3 个不同的数字,每次我在 "rid" = %d 和 "vs" = %d 上计算我想要的这个(具体的摆脱和具体的 vs)

SELECT count(*) as count FROM notification 
WHERE rid = 60 AND vs = 2 AND isN = 1 GROUP BY eId 

rid=>60,21=>6,22=>3,vs=>2,isN=>1  

(这就是我从上面得到的)

rid=>60,21=>6,22=>3,23=>0,33=>0,34=>0,35=>0,36=>0,41=>0,42=>0,vs=>2,isN=>1

(这就是我想要的。计数了八个,当然这个计数的数字在 eId 上不存在,所以我想返回为零)

4

3 回答 3

1

您需要的是一个包含您想要输出的所有值的驱动程序表。然后,您可以将其从外部连接到实际数据:

SELECT count(notification.eid) as count
FROM (select distinct eid
      from notification
     ) drivers left outer join
     (select *
      from notification
      WHERE rid = %d AND vs = %d AND isN = 1
     ) n
     on driver.eid = notification.eid
GROUP BY driver.eId

您还应该eidselect子句中包含 ,除非您依赖于输出的最终顺序(MySQL,与任何其他数据库不同,确实保证在 a 之后的结果顺序group by。)

于 2013-02-11T16:31:14.893 回答
1

这是获取指定结果集的一种方法:

 SELECT d.rid           AS `rid`
      , SUM(n.eid<=>21) AS `21`
      , SUM(n.eid<=>22) AS `22`
      , SUM(n.eid<=>23) AS `23`
      , SUM(n.eid<=>33) AS `33`
      , SUM(n.eid<=>34) AS `34`
      , SUM(n.eid<=>35) AS `35`
      , SUM(n.eid<=>36) AS `36`
      , SUM(n.eid<=>41) AS `41`
      , SUM(n.eid<=>42) AS `42`
      , d.vs            AS `vs`
      , d.isN           AS `isN`
   FROM ( SELECT %d AS rid, %d AS vs, 1 AS isN ) d
   LEFT
   JOIN notification n
     ON n.rid = d.rid
    AND n.vs  = d.vs
    AND n.isN = d.isN
  GROUP
     BY d.rid
      , d.vs
      , d.isN

注意:表达式(n.eid<=>21)是 的简写IF(n.eid=21,1,0),或者更符合 ANSI 标准CASE WHEN n.eid = 21 THEN 1 ELSE 0 END。这给出了 0 或 1,然后可以将其与SUM函数聚合。

您可以使用以下任何形式获得等效结果:

     , SUM(n.eid<=>21)                             AS `21`
     , COUNT(IF(n.eid=22,1,NULL))                  AS `22`
     , SUM(IF(n.eid=23,1,0))                       AS `23`
     , COUNT(CASE WHEN n.eid = 33 THEN 1 END)      AS `33`
     , SUM(CASE WHEN n.eid = 34 THEN 1 ELSE 0 END) AS `34`

我们在这里使用的“技巧”是我们保证别名为 as 的内联视图d将返回一行。然后我们使用 LEFT JOIN 运算符从notification表中提取所有“匹配”的行。这GROUP BY将强制所有这些行被折叠(聚合)回单行。我们正在对每一行使用条件测试来查看它是否包含在给定的计数中,“技巧”是为每一行返回一个 0 或 1,然后将所有 0 和1s 进行计数。

注意:如果您使用COUNT(expr)聚合,您希望expr当该行包含在计数中时返回非 NULL,并且当该行不包含在计数中时返回 NULL。

如果您使用 a SUM(expr),那么您希望expr在该行包含在计数中时返回 1,而在不包含时返回 0。(我们想要一个 0 而不是 NULL,这样我们就可以保证SUM(expr)在没有要包含的行时返回“零计数”(即 0 而不是 NULL)。(当然,我们可以使用IFNULL函数用 0 替换 NULL,但在这种情况下,它很简单,无需这样做。)


请注意,这种“计数”方法的一个优点是它可以轻松扩展以获得“组合”计数,或者在几个不同的计数中包含一行。例如

    , SUM(IF(n.eid IN (41,42),1,0)) AS `total_41_and_42`

将使我们得到 eid=41 和 eid=42 行的总数。(这不是一个很好的例子,因为我们可以通过将两个计数相加来轻松地在客户端计算它。但是如果您进行更精细的计数,并且想要将单行计数为多个,这确实会成为一个优势列 ...

   , SUM(IF(n.eid=42,1,0))            AS eid_42
   , SUM(IF(n.eid=42 AND foo=1,1,0)   AS eid_42_foo_1
   , SUM(IF(n.eid=42 AND foo=2,1,0))  AS eid_42_foo_2

我们只需“一次通过”notification表格即可获得所有这些单独的计数。如果我们尝试在 WHERE 子句中进行这些检查,我们可能需要多次通过表。

于 2013-02-11T17:05:18.377 回答
0

所以,基本上你要找的是这个?...

 SELECT rid,eid,vs, COUNT(*) FROM notification GROUP BY rid,eid,vs;
 +-----+-----+----+----------+
 | rid | eid | vs | COUNT(*) |
 +-----+-----+----+----------+
 |   0 |  22 |  2 |        2 |
 |   3 |  21 |  2 |        1 |
 |   3 |  22 |  2 |        2 |
 |  60 |  21 |  2 |        6 |
 |  60 |  22 |  2 |        3 |
 |  81 |  21 |  2 |        1 |
 |  81 |  22 |  2 |        3 |
 +-----+-----+----+----------+
 7 rows in set (0.11 sec)
于 2013-02-11T17:17:43.617 回答