Mysql 选择多列计数,但仅当列值大于0时才包括该计数

Mysql 选择多列计数,但仅当列值大于0时才包括该计数,mysql,Mysql,我不确定我在标题中是否正确解释了这个问题,但基本上我有一个表,可以节省玩家的出场时间: CREATE TABLE `stagetimes` ( `steamid` VARCHAR(32) CHARACTER SET utf8 NOT NULL DEFAULT '', `name` VARCHAR(32) CHARACTER SET utf8 DEFAULT NULL, `mapname` VARCHAR(32) CHARACTER SET utf8

我不确定我在标题中是否正确解释了这个问题,但基本上我有一个表,可以节省玩家的出场时间:

CREATE TABLE `stagetimes` 
  ( 
     `steamid` VARCHAR(32) CHARACTER SET utf8 NOT NULL DEFAULT '', 
     `name`    VARCHAR(32) CHARACTER SET utf8 DEFAULT NULL, 
     `mapname` VARCHAR(32) CHARACTER SET utf8 NOT NULL DEFAULT '', 
     `s1`      FLOAT DEFAULT '-1', 
     `s2`      FLOAT DEFAULT '-1', 
     `s3`      FLOAT DEFAULT '-1', 
     `s4`      FLOAT DEFAULT '-1', 
     `s5`      FLOAT DEFAULT '-1' 
  ) 
engine=innodb
ALTER TABLE `stagetimes`
ADD PRIMARY KEY (`steamid`,`mapname`);
这张表实际上上升到了s35,但为了简单起见,我忽略了其余部分

一旦有人完成阶段1,就会插入一个新行,其中包含他们的steamid、姓名、地图名称和阶段1时间,其余列为-1,并在他们击败其他阶段后进行更新。然而,并非每个地图都有5个阶段,有些可能只有4个或更少,因此显然,如果玩家的列值为-1,该阶段不存在或尚未完成,因此没有从-1更新时间

我想选择一个特定玩家已经完成的阶段总数作为计数;我提出了一个有效的查询,但它非常长,我想知道是否有其他方法可以实现这一点:

SELECT Sum(stages) 
FROM   ((SELECT Count(`s1`) AS `stages` 
         FROM   `stagetimes` 
         WHERE  `steamid` = 'STEAM_1:0:00000000' 
                AND `s1` > 0) 
        UNION ALL 
        (SELECT Count(`s2`) AS `stages` 
         FROM   `stagetimes` 
         WHERE  `steamid` = 'STEAM_1:0:00000000' 
                AND `s2` > 0) 
        UNION ALL 
        (SELECT Count(`s3`) AS `stages` 
         FROM   `stagetimes` 
         WHERE  `steamid` = 'STEAM_1:0:00000000' 
                AND `s3` > 0) 
        UNION ALL 
        (SELECT Count(`s4`) AS `stages` 
         FROM   `stagetimes` 
         WHERE  `steamid` = 'STEAM_1:0:00000000' 
                AND `s4` > 0) 
        UNION ALL 
        (SELECT Count(`s5`) AS `stages` 
         FROM   `stagetimes` 
         WHERE  `steamid` = 'STEAM_1:0:00000000' 
                AND `s5` > 0)) t1 
如果可以避免的话,我真的不想做35次

样本数据:

+-------------------+------------+---------------+--------+--------+--------+--------+--------+
|      steamid      |    name    |    mapname    |   s1   |   s2   |   s3   |   s4   |   s5   |
+-------------------+------------+---------------+--------+--------+--------+--------+--------+
|STEAM_1:0:20019070 |  fluffys   | surf_catrix   | 13.562 | 12.593 | 14.328 | 21.984 |   -1   |
|STEAM_1:0:20019070 |  fluffys   | surf_beginner |  2.753 |  9.185 | 14.406 | 23.359 | 11.343 |
+-------------------+------------+---------------+--------+--------+--------+--------+--------+
根据该数据,查询应返回9,因为有9个阶段的值不为-1

使用
SUM()
而不是
COUNT()
将其放入单个查询中。条件表达式为true时返回
1
,为false时返回
0
,因此您可以简单地添加它们

SELECT SUM((s1 > 0) + (s2 > 0) + (s3 > 0) + (s4 > 0) + (s5 > 0)) AS total_stages
FROM stagetimes
WHERE steamid = 'STEAM_1:0:00000000'

重新组织您的模式可能会更好。不要将每个阶段作为表中的一列,而是为每个阶段单独设置一行,将阶段编号作为一列。那么你就只有实际存在的阶段的行了。

顶部的
stagetimes
表与查询中的
ck\u wrcps
有什么关系?我的坏,修复了表名这对我不起作用,我在原始帖子中添加了一些示例数据,你的查询很可能只返回
2
,因为有2条记录,但我试图计算所有不是-1的阶段。我最初也用这种方式组织模式,但是有太多的记录,这是因为担心运算符优先级问题。每个条件都需要括号。