preface
The case keyword is used in two places in MySQL:
- Flow Control Functions – CASE Operator
- Flow Control Statements – CASE Statement
You cannot have an ELSE NULL clause in a CASE Statement and END it with END CASE, not END.
CASE statements are used in compound statements, such as stored procedures. CASE Operator is used as a function in a single statement.
This article focuses on the use of CASE Operator.
The basic syntax of case when
The first use:
CASE value
WHEN compare_value THEN result
[WHEN compare_value THEN result. ] [ELSE result]
END
Copy the code
Second usage:
CASE
WHEN condition THEN result
[WHEN condition THEN result. ] [ELSE result]
END
Copy the code
The difference between the two usages:
The first CASE syntax returns the result of the first branch where value=compare_value is true.
The second CASE syntax returns the result of the first branch where condition is true.
If no value=compare_value or condition is true, the ELSE is returned, or NULL is returned if there is no ELSE branch.
Case when
There must be no intersection between branches
This function is executed sequentially, with no overlap between conditions; It’s not that MySQL syntactically doesn’t allow intersections, but rather that once a successful match has been made the other branches don’t execute. If the logical relationship is not sorted out, the result of the query may not be the expected result.
The judgment of the NULL
The first use of CASE is to determine whether a field or expression is NULL.
Wrong way to write:
SELECT
CASE(` ` field|'expression')WHEN NULL THEN 'Result false'
ELSE 'Result is true'
END
FROM `table_name`
Copy the code
The correct way to write this is:
SELECT
CASE(` ` field|'expression')IS NULL
WHEN TRUE THEN 'Result is true'
ELSE 'Result false'
END
FROM `table_name`
Copy the code
= = = = = = = = = = = = = = =
The default value problem
It is interesting to see this usage in this blog post on mysql Case When.
Statement 1:
UPDATE categories
SET
display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END;
Copy the code
Statement 2:
UPDATE categories
SET
display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END
WHERE
id IN (1.2.3);
Copy the code
If you do not restrict ids with a WHERE statement, statement 1 sets the display_order field to NULL for all records whose ids are not 1, 2, or 3.
The value type returned by the branch can be inconsistent
SELECT
CASE
WHEN 5 % 3 = 0 THEN"Case 1"WHEN 5 % 3 = 1 THEN"Case 2"ELSE 12
END AS result;
Copy the code
This SQL statement is executed without error on the DataGrip, nor is it followed by a table name query. The return type of the branch is inconsistent. Should I not report an error?
I then executed the SQL statement with the JdbcTemplate and found that there was no error, ELSE branch value was converted to a string.
Sure enough MySQL is not rigorous ah!
At this point, I went back and took a closer look at the MySQL documentation and found that it was quite detailed about this situation.
Here’s a quick translation:
CASE functions return values that can be aggregated types of all resultant value types:
- If all values are of numeric type, then the aggregate type is also numeric:
- If at least one of the values is double, the result type is double.
- Otherwise, if at least one of the values is
DECIMAL
, then the type of result isDECIMAL
. - .
- .
- For all other types of combinations, the result is
VARCHAR
Type. - When a type is merged, it is ignored
NULL
The type to which the value belongs.
There are too many merge cases in the middle to list for space reasons. If you are interested, please go to operate_case.
Case when usage scenarios
- Translate the field meaning based on the condition
- Transfer line column
Field transformation
SELECT
name 'name',
age 'age'.CASE
WHEN age < 18 THEN 'young'
WHEN age < 30 THEN 'young'
WHEN age > = 30 AND age < 50 THEN 'middle'
ELSE 'older'
END 'Age group'
FROM
user_info;
Copy the code
A statement outputs multiple indicators
How many boys, how many girls, and how many of the boys pass, how many of the girls pass
The table structure is as follows: STU_SEX field 0 indicates male and 1 indicates female.
STU_CODE | STU_NAME | STU_SEX | STU_SCORE |
---|---|---|---|
XM | Xiao Ming | 0 | 88 |
XL | Little lei | 0 | 55 |
XF | Xiao feng | 0 | 45 |
XH | The little red | 1 | 66 |
XN | XiaoNi | 1 | 77 |
XY | Small Iraq | 1 | 99 |
SELECT
SUM (CASE WHEN STU_SEX = 0 THEN 1 ELSE 0 END) AS MALE_COUNT,
SUM (CASE WHEN STU_SEX = 1 THEN 1 ELSE 0 END) AS FEMALE_COUNT,
SUM (CASE WHEN STU_SCORE > = 60 AND STU_SEX = 0 THEN 1 ELSE 0 END) AS MALE_PASS,
SUM (CASE WHEN STU_SCORE > = 60 AND STU_SEX = 1 THEN 1 ELSE 0 END) AS FEMALE_PASS
FROM
THTF_STUDENTS
Copy the code
The table structure in this example is not very reasonable: name, gender, and score are all in the same table; However, I rarely see “sum” used with “case”. “sum” is usually used with “group”.
Transfer line column
- Show sales horizontally by month
- Horizontal display of grades by subject
CASE WHEN alone cannot convert rows to columns, and clauses such as SUM and GROUP BY need to be used.
Statistical results of all subjects
SELECT
st.stu_id 'student id',
st.stu_name 'name'.sum(CASE co.course_name WHEN 'College Chinese' THEN sc.scores ELSE 0 END ) 'College Chinese'.sum(CASE co.course_name WHEN New Horizons English THEN sc.scores ELSE 0 END ) New Horizons English.sum(CASE co.course_name WHEN 'Discrete mathematics' THEN sc.scores ELSE 0 END ) 'Discrete mathematics'.sum(CASE co.course_name WHEN 'Probability theory' THEN sc.scores ELSE 0 END ) 'Probability theory'.sum(CASE co.course_name WHEN 'Linear algebra' THEN sc.scores ELSE 0 END ) 'Linear algebra'.sum(CASE co.course_name WHEN 'Advanced Mathematics' THEN sc.scores ELSE 0 END ) 'Advanced Mathematics'
FROM
edu_student st
LEFT JOIN edu_score sc ON st.stu_id = sc.stu_id
LEFT JOIN edu_courses co ON co.course_no = sc.course_no
GROUP BY
st.stu_id
ORDER BY
NULL;
Copy the code
The sum of each department’s monthly performance
SELECT
t1.dep,
t2.depname,
SUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) ASJanuarySUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) ASJanuarySUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) ASJanuaryFROM
table_1 t1
LEFT JOIN table_2 t2 ON t1.dep = t2.dep
GROUP BY
t1.dep;
Copy the code
SQL optimization
Examples of optimized statistical analysis
SQL > select * from sum case when;
SELECT
(
SELECT SUM(total_fee)
FROM mall_order SS
WHERE SS.create_time = S.create_time AND SS.payment_method = 1
) AS 'zhifubaoTotalOrderAmount',
(
SELECT COUNT(*)
FROM mall_order SS
WHERE SS.create_time = S.create_time AND SS.payment_method = 1
) AS 'zhifubaoTotalOrderNum',
(
SELECT SUM(total_fee)
FROM mall_order SS
WHERE SS.create_time = S.create_time AND SS.payment_method = 2
) AS 'weixinTotalOrderAmount',
(
SELECT COUNT(*)
FROM mall_order SS
WHERE SS.create_time = S.create_time AND SS.payment_method = 2
) AS 'weixinTotalOrderNum'
FROM mall_order S
WHERE S.create_time > '2016-05-01' AND S.create_time < '2016-08-01'
GROUP BY
S.create_time
ORDER BY
S.create_time ASC;
Copy the code
Execution: 50W pieces of data, about 10s; Full table scan, 4 DEPENDENT SUBQUERY, DEPENDENT on external query.
After using sum case when:
SELECT
S.create_time,
sum(case when S.payment_method =1 then 1 else 0 end) as 'zhifubaoOrderNum'.sum(case when S.payment_method =1 then total_fee else 0 end) as 'zhifubaoOrderAmount'.sum(case when S.payment_method =2 then 1 else 0 end) as 'weixinOrderNum'.sum(case when S.payment_method =2 then total_fee else 0 end) as 'weixinOrderAmount'
FROM
mall_order S
WHERE
S.create_time > '2015-05-01' and S.create_time < '2016-08-01'
GROUP BY
S.create_time
ORDER BY
S.create_time asc;
Copy the code
Execution: Scan 50W pieces of data in the whole table for about 1s; Iterate through the entire table once to get the result.
Another example of optimization
SQL > alter TABLE SQL > alter table SQL
SELECT
uid,
sum(power) powerup
FROM t1
WHERE
date> ='2017-03-31' AND
UNIX_TIMESTAMP(STR_TO_DATE(concat(date.' '.hour),'%Y-%m-%d %H'))> =1490965200 AND
UNIX_TIMESTAMP(STR_TO_DATE(concat(date.' '.hour),'%Y-%m-%d %H'))<1492174801 AND
aType in (1.6.9)
GROUP BY
uid;
Copy the code
When the table is designed, the date and hour in the date and time are separated into two columns, and then merged into a new condition in the query. This results in a very inefficient SQL with full table scans, no indexes, temporary tables, and extra sorting.
Optimized SQL:
SELECT
uid,
sum(powerup+powerup1)
FROM
(
SELECT uid,
CASE
WHEN concat(date.' '.hour) > ='the 2017-03-24 13:00' THEN power ELSE '0'
END AS powerup,
CASE
WHEN concat(date.' '.hour) < 'the 2017-03-25 13:00' THEN power ELSE '0'
END AS powerup1
FROM t1
WHERE date > = '2017-03-24' AND date AND aType in (1.6.9)
) a
GROUP BY
uid;
Copy the code
With case when optimization, the original index on date can be used.
conclusion
I don’t like using case WHEN in SQL statements in business code for two reasons:
- Not very readable
- Poor maintainability
But when you do statistical analysis, you use these functions and say, wow!
reference
- Dev.mysql.com/doc/refman/…
- Dev.mysql.com/doc/refman/…
- www.cnblogs.com/echojson/p/…
- Blog.csdn.net/qq_16142851…
- Blog.csdn.net/u013514928/…
- www.cnblogs.com/chenduzizho…
- www.cnblogs.com/echojson/p/…
- Blog.csdn.net/qq_16142851…
- My.oschina.net/u/1187675/b…
- Blog.csdn.net/weixin_3246…
- Blog.csdn.net/rongtaoup/a…