предисловие
В MySQL есть два места, где используются ключевые слова.case
:
существуетCASE Statement
не может иметь вELSE NULL
оговорка и сEND CASE
конец вместоEND
.
CASE Statement
В основном используется в составных операторах, таких как хранимые процедуры; иCASE Operator
Он используется как функция в одном операторе.
Эта статья в основном знакомит сCASE Operator
Применение.
Основной синтаксис случая, когда
Первое использование:
CASE value
WHEN compare_value THEN result
[WHEN compare_value THEN result ...]
[ELSE result]
END
Второе использование:
CASE
WHEN condition THEN result
[WHEN condition THEN result ...]
[ELSE result]
END
Разница между двумя вариантами использования:
ПервыйCASE
Синтаксис возвращает первоеvalue=compare_value
дляtrue
результат ветки.
второйCASE
Синтаксис возвращает первоеcondition
дляtrue
результат ветки.
если нет ни одногоvalue=compare_value
илиcondition
дляtrue
, то вернетсяELSE
соответствующий результат, если нетELSE
ветвь, затем возвратNULL
.
Меры предосторожности на тот случай, когда
Не может быть пересечения между ветвями
Эта функция выполняется последовательно, и между каждым условием не может быть пересечения; дело не в том, что синтаксис MySQL не допускает пересечения, а в том, что после успешного совпадения другие ветви выполняться не будут. Если логическая связь не устранена, результаты запроса могут не соответствовать ожиданиям.
НУЛЕВОЕ решение
существуетCASE
При первом использовании , если вы хотите судить, является ли поле или выражениеNULL
письма.
Неправильное написание:
SELECT
CASE (`字段`|`表达式`)
WHEN NULL THEN '结果为假'
ELSE '结果为真'
END
FROM `table_name`
Правильное написание:
SELECT
CASE (`字段`|`表达式`) IS NULL
WHEN TRUE THEN '结果为真'
ELSE '结果为假'
END
FROM `table_name`
Причина, по которой это должно быть написано таким образом, заключается в следующем: MySQL неNULL
Суждение не может прямо использовать знак равенства=
, но использоватьIS NULL
илиIS NOT NULL
.
Проблема со значениями по умолчанию
существуетЯма случая mysql, когдаИнтересно увидеть это использование в этом блоге.
Заявление 1:
UPDATE categories
SET
display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END;
Заявление 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);
если неwhere
пара операторовid
ограничение, то оператор 1 будетid
не для1, 2, 3
всех рекордовdisplay_order
поля настроены наNULL
.
Тип значения, возвращаемый ветвью, может быть несогласованным
SELECT
CASE
WHEN 5 % 3 = 0 THEN "情况1"
WHEN 5 % 3 = 1 THEN "情况2"
ELSE 12
END AS result;
существуетDataGrip
выполнить это наSQL
Оператор не сообщает об ошибке, а запрос, за которым следует имя таблицы, не сообщает об ошибке. Увидев этот результат, я сломался.Тип возвращаемого значения ветки несовместим.Не должно ли быть сообщение об ошибке?
Затем я используюJdbcTemplate
выполнить этоSQL
заявление, обнаружил, что ошибки не было,ELSE
Значение ветки преобразуется в строку.
В самом делеMySQL
Несерьезно!
В этот момент я обернулся и посмотрел поближе.Документация по MySQL, и обнаружил, что документация очень подробно описывает эту ситуацию.
Вот простой перевод:
CASE
Возвращаемое значение функции представляет собой агрегированный тип всех результирующих типов значений:
- Если тип всех значений числовой, то тип агрегата тоже числовой:
- Если хотя бы одно из значений двойное, то тип результата двойной.
- В противном случае, если хотя бы одно значение
DECIMAL
, то тип результатаDECIMAL
. - ......
- ......
- Для всех других типов комбинаций результат
VARCHAR
Типы. - Когда типы объединяются, они игнорируются
NULL
Тип, которому принадлежит значение.
В середине слишком много типов слияний, поэтому я не буду перечислять их по одному из-за нехватки места.Если вам интересно, перейдите по ссылке:operate_case.
Сценарий использования случая, когда
- Преобразование значений полей на основе условий
- строка в столбец
преобразование поля
SELECT
name '姓名',
age '年龄',
CASE
WHEN age < 18 THEN '少年'
WHEN age < 30 THEN '青年'
WHEN age >= 30 AND age < 50 THEN '中年'
ELSE '老年'
END '年龄段'
FROM
user_info;
Один оператор для вывода нескольких индикаторов
Структура таблицы следующая: в поле STU_SEX 0 означает мальчиков, 1 — девочек.
STU_CODE | STU_NAME | STU_SEX | STU_SCORE |
---|---|---|---|
XM | Сяо Мин | 0 | 88 |
XL | Сяолэй | 0 | 55 |
XF | Сяофэн | 0 | 45 |
XH | немного красный | 1 | 66 |
XN | Сяо Ни | 1 | 77 |
XY | Сяойи | 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
Структура таблицы в этом примере не очень разумна: имя, пол и оценка помещаются в одну таблицу; ноsum
а такжеcase
Я редко видел их вместе,sum
не все общее иgroup
использовать вместе?
строка в столбец
- Отображение продаж горизонтально по месяцам
- Горизонтальное отображение оценок по предметам
невиновныйCASE WHEN
Невозможно преобразовать строки в столбцы и необходимо сотрудничатьSUM
а такжеGROUP BY
Использование оговорки etc.
Статистика по каждому предмету
SELECT
st.stu_id '学号',
st.stu_name '姓名',
sum(CASE co.course_name WHEN '大学语文' THEN sc.scores ELSE 0 END ) '大学语文',
sum(CASE co.course_name WHEN '新视野英语' THEN sc.scores ELSE 0 END ) '新视野英语',
sum(CASE co.course_name WHEN '离散数学' THEN sc.scores ELSE 0 END ) '离散数学',
sum(CASE co.course_name WHEN '概率论' THEN sc.scores ELSE 0 END ) '概率论',
sum(CASE co.course_name WHEN '线性代数' THEN sc.scores ELSE 0 END ) '线性代数',
sum(CASE co.course_name WHEN '高等数学' THEN sc.scores ELSE 0 END ) '高等数学'
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;
Сумма месячной производительности каждого отдела
SELECT
t1.dep,
t2.depname,
SUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) AS 一月,
SUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) AS 一月,
SUM(CASE mon WHEN '一月' THEN yj ELSE 0 END) AS 一月,
FROM
table_1 t1
LEFT JOIN table_2 t2 ON t1.dep = t2.dep
GROUP BY
t1.dep;
SQL-оптимизация
Примеры оптимального статистического анализа
использоватьsum case when
предыдущийSQL
:
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;
Выполнение: 50 Вт данных, около 10 с; полное сканирование таблицы, 4 подзапросаDEPENDENT SUBQUERY
, зависит от внешнего запроса.
использовать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;
Ситуация с выполнением: вся таблица сканирует 50 Вт данных, около 1 с; результат можно получить, пройдя всю таблицу один раз.
оригинальный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;
Описание ситуации: Таблица разработана с датой и временем вdate
а такжеhour
Он разделяется на два столбца, а затем при запросе объединяется в новое условие, что приводит к очень низкой эффективности SQL, полному просмотру таблицы, отсутствию индекса, временной таблицы и дополнительной сортировке.
оптимизированныйSQL
:
SELECT
uid,
sum(powerup+powerup1)
FROM
(
SELECT uid,
CASE
WHEN concat(date,' ',hour) >='2017-03-24 13:00' THEN power ELSE '0'
END AS powerup,
CASE
WHEN concat(date,' ',hour) < '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;
использоватьcase when
После оптимизации оригиналdate
Можно использовать приведенный выше индекс.
Суммировать
Лично мне не нравится работать в бизнес-кодеSQL
используется в предложенияхcase when
, по двум причинам:
- не очень читабельно
- Плохая ремонтопригодность
Однако при статистическом анализе использование этого типа функций будет вздыхать: действительно ароматно!
использованная литература
- Dev.MySQL.com/doc/Furious/…
- Dev.MySQL.com/doc/Furious/…
- Блог woohoo.cn на.com/echo JSON/afraid/…
- blog.CSDN.net/QQ_16142851…
- blog.CSDN.net/U013514928/…
- Woo Woo.cn blog on.com/ Воспользуйтесь животом...
- Блог woohoo.cn на.com/echo JSON/afraid/…
- blog.CSDN.net/QQ_16142851…
- no.OSCHINA.net/U/1187675/no…
- blog.CSDN.net/WeChat_3246…
- blog.CSDN.net/velvet U disk/ah…