暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL,case when你真的会用吗?附避坑指南

程序员实用技能 2021-07-22
2617

case when 的语法有如下两种:

    1 CASE WHEN [expr] THEN [result1]…
      ELSE [default] END
    2 CASE [col_name] WHEN [value1/expr1] THEN [result1]…
    ELSE [default] END

    注意:

    1. 第一种语法最常用,可比较等于、范围的条件。遇到第一个满足条件的即返回,不再往下比较,如果没有满足的条件则返回else里的结果,如果没有else则返回NULL。

    2. 第二种语法不常用,只能比较等于的条件。when后面如果是值,则是表示等于的意思,"="可以不用写,遇到满足条件的才返回,如果没有满足的条件则返回else里的结果,如果没有else则返回NULL。when后面如果是表达式,不管when的条件是否满足,都是返回else里的结果,如果没有else则返回NULL。

    3. when后面要么是表达式,要么是值,不然报错。如果是“=‘101’“或者“>=1000” 这样既不是表达式,也不是值,则执行时报错。


    表结构:

      CREATE TABLE `staff` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
      `name` varchar(50) NOT NULL COMMENT '姓名',
      `dept_id` varchar(10) DEFAULT NULL COMMENT '部门id',
      `salary` double DEFAULT NULL COMMENT '工资',
      `sex` int(11) DEFAULT NULL COMMENT '性别,1是男生,0是女生',
      `created_time` datetime DEFAULT NULL COMMENT '创建时间',
      `updated_time` datetime DEFAULT NULL COMMENT '更新时间',
      PRIMARY KEY (`id`)
      ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='职员表'   

      现有记录:

        mysql> select * from staff ;
        +----+-------+---------+--------+------+---------------------+---------------------+
        | id | name | dept_id | salary | sex | created_time | updated_time |
        +----+-------+---------+--------+------+---------------------+---------------------+
        | 1 | Tom | 101 | 2500 | 1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 2 | Tonny | 101 | 3500 | 1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 3 | Bob | 101 | 3500 | 0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 4 | Rob | 101 | 4500 | 1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 5 | Sudey | 101 | 5500 | 0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 6 | Sunny | 102 | 5500 | 1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 7 | Sedey | 102 | 3500 | 0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 8 | Bobby | 102 | 4500 | 0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 9 | Weedy | 103 | 4500 | 1 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        | 10 | Jimme | 104 | 5500 | 0 | 2020-03-08 18:37:55 | 2020-03-08 18:37:55 |
        +----+-------+---------+--------+------+---------------------+---------------------+
        10 rows in set (0.00 sec)


        我们想根据salary区分类别:


        1. 使用

          CASE WHEN [expr] THEN [result1]
          ELSE [default] END

          如下语句的结果符合期望:

          when后面是表达式

            select
            name,
            salary,
            case
            when salary >= 5000 then 'T1'
            when salary >= 4000 then 'T2'
            when salary >= 3000 then 'T3'
            when salary >= 2000 then 'T4'
            else 'T5'
            end as salary_level
            from staff ;
            +-------+--------+--------------+
            | name | salary | salary_level |
            +-------+--------+--------------+
            | Tom | 2500 | T4 |
            | Tonny | 3500 | T3 |
            | Bob | 3500 | T3 |
            | Rob | 4500 | T2 |
            | Sudey | 5500 | T1 |
            | Sunny | 5500 | T1 |
            | Sedey | 3500 | T3 |
            | Bobby | 4500 | T2 |
            | Weedy | 4500 | T2 |
            | Jimme | 5500 | T1 |
            +-------+--------+--------------+
            10 rows in set (0.00 sec)

            如下语句的结果则不符合期望:

            顺序弄反了,是返回第一个符合条件的结果

              select
              name,
              salary,
              case
              when salary >= 2000 then 'T1'
              when salary >= 3000 then 'T2'
              when salary >= 4000 then 'T3'
              when salary >= 5000 then 'T4'
              else 'T5'
              end as salary_level
              from staff ;
              +-------+--------+--------------+
              | name | salary | salary_level |
              +-------+--------+--------------+
              | Tom | 2500 | T1 |
              | Tonny | 3500 | T1 |
              | Bob | 3500 | T1 |
              | Rob | 4500 | T1 |
              | Sudey | 5500 | T1 |
              | Sunny | 5500 | T1 |
              | Sedey | 3500 | T1 |
              | Bobby | 4500 | T1 |
              | Weedy | 4500 | T1 |
              | Jimme | 5500 | T1 |
              +-------+--------+--------------+
              10 rows in set (0.00 sec)

              2. 使用

                CASE [col_name] WHEN [value1] THEN [result1]…
                ELSE [default] END

                如下语句的结果符合期望:

                when后面是值

                  select
                  name,
                  salary,
                  case salary
                  when 2500 then 'T1'
                  when 3500 then 'T2'
                  when 4500 then 'T3'
                  when 5500 then 'T4'
                  else 'T5'
                  end as salary_level
                  from staff ;
                  +-------+--------+--------------+
                  | name | salary | salary_level |
                  +-------+--------+--------------+
                  | Tom | 2500 | T1 |
                  | Tonny | 3500 | T2 |
                  | Bob | 3500 | T2 |
                  | Rob | 4500 | T3 |
                  | Sudey | 5500 | T4 |
                  | Sunny | 5500 | T4 |
                  | Sedey | 3500 | T2 |
                  | Bobby | 4500 | T3 |
                  | Weedy | 4500 | T3 |
                  | Jimme | 5500 | T4 |
                  +-------+--------+--------------+
                  10 rows in set (0.00 sec)

                  如下语句则报错:

                  when后面既不是表达式,也不是值

                    select
                    name,
                    salary,
                    case salary
                    when >= 2000 then 'T1'
                    when >= 3000 then 'T2'
                    when >= 4000 then 'T3'
                    when >= 5000 then 'T4'
                    else 'T5'
                    end as salary_level
                    from staff ;
                    -- ERROR 1064 (42000): You have an error in your SQL syntax;

                    3. 使用

                      CASE [col_name] WHEN [expr1] THEN [result1]…
                      ELSE [default] END

                      如下语句不报错,但是结果不符合期望:

                      when后面是表达式,不管when的条件是否满足,都是返回else里的结果

                        select
                        name,
                        salary,
                        case salary
                        when salary=2500 then 'T1'
                        when salary=3500 then 'T2'
                        when salary=4500 then 'T3'
                        when salary=5500 then 'T4'
                        else 'T5'
                        end as salary_level
                        from staff ;
                        +-------+--------+--------------+
                        | name | salary | salary_level |
                        +-------+--------+--------------+
                        | Tom | 2500 | T5 |
                        | Tonny | 3500 | T5 |
                        | Bob | 3500 | T5 |
                        | Rob | 4500 | T5 |
                        | Sudey | 5500 | T5 |
                        | Sunny | 5500 | T5 |
                        | Sedey | 3500 | T5 |
                        | Bobby | 4500 | T5 |
                        | Weedy | 4500 | T5 |
                        | Jimme | 5500 | T5 |
                        +-------+--------+--------------+
                        10 rows in set (0.00 sec)

                        如下语句不报错,但是结果不符合期望:

                        when后面是表达式,已经把else语句注释掉了,不管when的条件是否满足,都是返回NULL

                          select
                          name,
                          salary,
                          case salary
                          when salary=2500 then 'T1'
                          when salary=3500 then 'T2'
                          when salary=4500 then 'T3'
                          when salary=5500 then 'T4'
                          -- else 'T5'
                          end as salary_level
                          from staff ;
                          +-------+--------+--------------+
                          | name | salary | salary_level |
                          +-------+--------+--------------+
                          | Tom | 2500 | NULL |
                          | Tonny | 3500 | NULL |
                          | Bob | 3500 | NULL |
                          | Rob | 4500 | NULL |
                          | Sudey | 5500 | NULL |
                          | Sunny | 5500 | NULL |
                          | Sedey | 3500 | NULL |
                          | Bobby | 4500 | NULL |
                          | Weedy | 4500 | NULL |
                          | Jimme | 5500 | NULL |
                          +-------+--------+--------------+
                          10 rows in set (0.00 sec)

                          以上是本人亲测,之前使用时有些迷惑第二种语法,如今终于明白了。下期分享case when在分组统计中的实际用法。

                          当前版本:

                            mysql> select version();
                            +-----------+
                            | version() |
                            +-----------+
                            | 5.7.28 |
                            +-----------+
                            1 row in set (0.01 sec)


                            mysql>

                            历史文章:

                            MySQL常用面试题(一)

                            Mysql 不走索引的情况

                            Mysql查询年的第多少周

                            Mysql,replace into,存在则更新,不存在则插入

                            Mysql修改字段名、字段类型、指定位置添加字段、删除字段、修改表名、表注释

                            「欢迎关注,一起学习,一起进步」

                            文章转载自程序员实用技能,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                            评论