Data Query Language,用于查询数据库的表中数据,是数据库中最为核心的语言,使用频率最高
SELECT * FROM 表名称
SELECT * FROM patient
# 查询 patient 病人表中的所有字段 * 表示所有字段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JjUiypof-1680502580614)(./assets/image-20230402180217861.png)]
SELECT 字段1,字段2,字段n FROM 表名称
SELECT patientID,patientName,gender FROM patient
# 查询 patient 病人表中的部分字段(多个字段之间使用,分隔)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMvUJ5ff-1680502580617)(./assets/image-20230402180548009.png)]
有的时候我们不想让用户看到所有的信息,比如用户密码这类的隐私信息,我们就可以通过写具体的字段,就只查询部分信息
在开发中,推荐使用以查询部分列的方式代替
SELECT *
查询全部列,可提高执行效率并养成良好编码习惯
SELECT 字段列表 FROM 表名 AS 表的别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAFZanNq-1680502580617)(./assets/image-20230402185049461.png)]
SELECT 字段1 AS 别名,字段2 FROM 表名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZnhTHvP-1680502580617)(./assets/image-20230402185113942.png)]
SELECT 字段列表 FROM 表名 表的别名;
# 中间是空格
为某个表命名了别名后,在 SELECT 语句中出现该表的字段需要指定表名时,就必须统一使用该表的别名;否则将产生语法错误
运算符是一种符号,用来进行列间或变量之间的比较和数学运算
MySQL 常的运算符
运算符 | 作用 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ 或 DIV | 除法 |
% 或 MOD | 取余 |
在除法运算和模运算中,如果除数为0,将是非法除数,返回结果为 NULL
符号 | 描述 | 备注 |
---|---|---|
= | 等于 | |
<>, != | 不等于 | |
> | 大于 | |
< | 小于 | |
<= | 小于等于 | |
>= | 大于等于 | |
BETWEEN | 在两值之间 | |
NOT BETWEEN | 不在两值之间 | |
IN | 在集合中 | |
NOT IN | 不在集合中 | |
<=> | 严格比较两个NULL值是否相等 | 两个操作码均为NULL时,其所得值为1;而当一个操作码为NULL时,其所得值为0 |
LIKE | 模糊匹配 | |
REGEXP 或 RLIKE | 正则式匹配 | |
IS NULL | 为空 | |
IS NOT NULL | 不为空 |
运算符号 | 作用 |
---|---|
NOT 或 ! | 逻辑非 |
AND | 逻辑与 |
OR | 逻辑或 |
XOR | 逻辑异或 |
逻辑运算符用来判断表达式的真假。如果表达式是真,结果返回 1。如果表达式是假,结果返回 0
运算符号 | 作用 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
! | 取反 |
<< | 左移 |
>> | 右移 |
位运算符是在二进制数上进行计算的运算符。位运算会先将操作数变成二进制数,进行位运算。然后再将计算结果从二进制数变回十进制数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HCbQP5oy-1680502580618)(./assets/1011652-20170416163043227-1936139924.png)]
如果我们查询时,并不想显示所有的用户信息,只要查出满足指定条件的部分用户,或者精确到某一个用户的信息,就需要使用到 WHERE 关键字对 sql 语句增加查询条件
SELECT * FROM patient WHERE patient.patientID = 1
# 通过患者 ID 精确查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XMiGzgAa-1680502580618)(./assets/image-20230402181442241.png)]
这里我们就把患者 ID 作为查询条件,查询出患者 ID 为 1 的患者信息
SELECT * FROM patient WHERE patient.patientID < 10
# 查询病人 ID 小于 10 的患者信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BdHWpCxV-1680502580618)(./assets/image-20230402182833603.png)]
SELECT * FROM patient WHERE patientName ='玄子'
# 查询所有病人姓名为玄子的患者信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSGaQyMy-1680502580619)(./assets/image-20230402224936557.png)]
如果查询条件中包含的条件不止一个,则条件根据逻辑关系的不同可以分为与
条件和或
条件两种
与
条件表示要求同时满足两个以上的条件,使用 AND 关键字可以构造与
条件。
或
条件表示几个条件中只需满足其中一个的条件,使用 OR 关键字可以构造或
条件
AND
SELECT * FROM patient WHERE patientName ='玄子' AND address='长春市'
# 多条件查询 姓名为 玄子 且住址为 长春市
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XzsP9Q2Z-1680502580619)(./assets/image-20230402230857608.png)]
SELECT * FROM patient WHERE patientName ='玄子' OR address='长春市'
# 多条件查询 姓名为 玄子 '或者' 住址为 长春市
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5vDB9Bh-1680502580619)(./assets/image-20230402231059106.png)]
姓名 和 住址 这两个条件满足一个即可
SELECT * FROM patient ORDER BY birthDate
# 通过病人的出生年月进行排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ebkqs3C5-1680502580620)(./assets/image-20230402183208506.png)]
这里我们使用 ORDER BY 关键字,对病人的出生年月进行排序,默认是从小到大,也就是
升序排列
SELECT * FROM patient ORDER BY birthDate DESC
# 通过病人的出生年月进行降序排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rr9UxEd3-1680502580620)(./assets/image-20230402183508864.png)]
使用降序排列只需要 在最后加上一个
DESC
关键字即可升序排序后面其实也有一个关键字
ASC
不过ORDER BY
默认就是升序排列,所以ASC
加不加都可以
SELECT * FROM patient ORDER BY birthDate ASC,patientID DESC
# 通过病人的出生年月和ID进行多字段排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1Hnmco6-1680502580620)(./assets/image-20230402183948955.png)]
如果想要对多个字段进行排序,可直接使用
,
分隔。然后写第二个需要排序的字段和排序方式即可
MySQL 中将一些常用的数据处理操作封装起来,作为函数提供给程序员使用,可以提高程序员开发效率
MySQ L支持的常用函数
字符串函数
时间日期函数
聚合函数
数学函数
函数名 | 作用 | 举例 |
---|---|---|
CONCAT(str1,str2,strn) | 连接字符串str1、str2、strn为一个完整字符串 | SELECT CONCAT( ‘MySQL’,’ is powerful.'); 返回:MySQL is powerful. |
LOWER(str) | 将字符串str中所有字符变为小写 | SELECT LOWER( ‘MySQL is powerful.’); 返回:mysql is powerful. |
UPPER(str) | 将字符串str中所有字符变为大写 | SELECT UPPER( ‘MySQL is powerful.’); 返回:MYSQL IS POWERFUL. |
SUBSTRING(str,num,len) | 返回字符串str的第num个位置开始长度为len的子字符串 | SELECT SUBSTRING( ‘MySQL is powerful.’,10,8); 返回:powerful |
INSERT(str,pos,len,newstr) | 将字符串str从pos位置开始,len个字符长的子串替换为字符串newstr | SELECT INSERT( ‘MySQL is powerful.’,10,0,'very '); 返回:MySQL is very powerful. |
函数名 | 作用 | 举例(部分结果与当前日期有关) |
---|---|---|
CURDATE() | 获取当前日期 | SELECT CURDATE(); 返回:2020-08-03 |
CURTIME() | 获取当前时间 | SELECT CURTIME(); 返回:16:54:40 |
NOW() | 获取当前日期和时间 | SELECT NOW(); 返回:2020-08-03 16:55:00 |
WEEK(date) | 返回日期date为一年中的第几周 | SELECT WEEK(NOW()); 返回:31 |
YEAR(date) | 返回日期date的年份 | SELECT YEAR(NOW()); 返回:2020 |
HOUR(time) | 返回时间time的小时值 | SELECT HOUR(NOW()); 返回:16 |
MINUTE(time) | 返回时间time的分钟值 | SELECT MINUTE(NOW()); 返回:56 |
DATEDIFF(date1,date2) | 返回日期参数date1和date2之间相隔的天数 | SELECT DATEDIFF(NOW(), ‘2019-8-8’); 返回:361 |
ADDDATE(date,n) | 计算日期参数date加上n天后的日期 | SELECT ADDDATE(NOW(), 5); 返回:2020-08-07 16:57:28 |
UNIX_TIMESTAMP(date) | 将日期转换成时间戳 | SELECT UNIX_TIMESTAMP(‘2020-9-1’); 返回:1598889600 |
DATE_ADD(d,INTERVAL expr type) | 计算起始日期 d 加上一个时间段后的日期 | SELECT DATE_ADD(‘2017-06-15’, INTERVAL 10 DAY); 返回:2017-06-25 |
DATE_ADD(d,INTERVAL expr type)
type 参数可以是下列值:MICROSECOND,SECOND,MINUTE,HOUR,DAY,WEEK,MONTH,QUARTER,YEAR,SECOND_MICROSECOND,MINUTE_MICROSECOND,MINUTE_SECOND,HOUR_MICROSECOND,HOUR_SECOND,HOUR_MINUTE,DAY_MICROSECOND,DAY_SECOND,DAY_MINUTE,DAY_HOUR,YEAR_MONTH
函数名 | 作用 |
---|---|
COUNT() | 返回某字段的行数 |
MAX() | 返回某字段的最大值 |
MIN() | 返回某字段的最小值 |
SUM() | 返回某字段的和 |
AVG() | 返回某字段的平均值 |
函数名 | 作用 | 举例 |
---|---|---|
CEIL(x) | 返回大于或等于数值x的最小整数 | SELECT CEIL(-2.1); 返回:32 |
FLOOR(x) | 返回小于或等于数值x的最大整数 | SELECT FLOOR(-2.1); 返回:-3 |
RAND() | 返回0~1间的随机数 | SELECT RAND(); 返回:0.15013303621684485 |
MySQL 中还有许多专业领域或不常用的函数,想具体了解见文章附件:
第八章 8.4 MySQL 函数
如果我们想要对,查询结果分组,比如按照,考试的科目ID 进行分组。就要使用GROUP BY 关键字对 subjectNo
进行分组,首先我们可以看到成绩表中有四个字段分别是studentNo 学生学号
,subjectNo 课程编号
,examDate 考试日期
,studentResult 考试成绩
。其中subjectNo
有三个编号我们就可以对其分组查询查出这三个编号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqJitzDm-1680502580621)(./assets/image-20230402190256908.png)]
SELECT subjectNo FROM result GROUP BY subjectNo
# 分组考试成绩表中的科目编号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4AVB7tT-1680502580621)(./assets/image-20230402190524327.png)]
这样分组就只能看到成绩表中的科目 ID,并不能查询其他字段,所以我们通常搭配
聚合函数
使用
SELECT subjectNo,AVG(studentResult) FROM result GROUP BY subjectNo
# 分组科目编号,查询对应科目考试成绩的平均分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oH1RLfj8-1680502580621)(./assets/image-20230402231713206.png)]
我们在使用 GROUP BY 分组后还想要进一步筛选查询结果,就需要使用 HAVING 关键字进一步筛选,这里并不能使用 WHERE
SELECT subjectNo,AVG(studentResult) AS avg FROM result GROUP BY subjectNo HAVING avg >60
# 分组科目编号,查询对应科目考试成绩的平均分 后继续筛选 成绩在 60 分以上的 科目编号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uglZmU7w-1680502580621)(./assets/image-20230402231957986.png)]
SELECT <字段名列表>
FROM <表名或视图>
[WHERE <查询条件>]
[GROUP BY <分组的字段名>] [HAVING <条件>]
[ORDER BY <排序的字段名> [ASC 或 DESC]]
[LIMIT [位置偏移量,]行数];
SELECT * FROM patient LIMIT 5,5
# 位置偏移量:第1条记录的位置偏移量是0,第2条记录的位置偏移量是1……
# 行数:显示记录的条数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4cIne1kH-1680502580622)(./assets/image-20230402233340898.png)]
使用LIMIT子句时,第1条记录的位置是0!
LIMIT 子句经常和 ORDER BY 子句一起使用,即先对查询结果进行排序,再根据 LIMIT 子句的参数返回指定的数据
SELECT * FROM patient LIMIT (n-1)*m,m
# 每页 m 个第 n 页
模糊查询一般使用关键字 LIKE 主要用于匹配列中的数据
通配符 | 解释 | 示例 |
---|---|---|
_ | 一个字符 | A LIKE ‘V_’,则符合条件的A如“VR”、“VC”等 |
% | 任意长度的字符串 | B LIKE ‘SQL%’,则符合条件的A如“SQL Server”、“SQL Server高级编程”等 |
[] | 括号中所指定范围内的一个字符 | C LIKE ‘900[1-2]’,则符合条件的C如“9001”或“9002” |
[^] | 不在括号中所指定范围内的任意一个字符 | D LIKE ‘900[^1-2 ]’,则符合条件的D如“9003”或“9007”等 |
select * from Students where StudentName like '张%'
# 名字以张开头的人
select * from Students where StudentName like '%张'
# 名字以张结尾的人
select * from Students where StudentName like '%张%'
# 名字中包含张的人
select * from Students where StudentName like '张_'
# 名字为张姓的单名人
select * from Students where StudentName like '张[1-4]'
# 查询结果为张姓的张1到张4
select * from Students where StudentName like '张[^1-4]'
# 查询结果为张姓的除了张1到张4的所有张姓单名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VW6cXuNi-1680502580622)(./assets/image-20230402234207243.png)]
匹配的字符串必须加单引号或者双引号
默认情况下,LIKE 关键字匹配字符串时候不区分大小写,可以在 LIKE 关键字后添加 BINARY 关键字来区分大小写。
如果查询内容中有通配符字符,就需要加转义字符
\
SELECT 字段 FROM 表名 WHERE 列名 [NOT] BETWEEN 起始值 AND 最终值
SELECT * FROM patient WHERE patient.patientID BETWEEN 5 AND 15
# 查询 ID 在 5 到 15 的患者信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xVigEVZS-1680502580622)(./assets/image-20230402235352933.png)]
NOT 可选参数,表示取反
查询指定范围内所有值,包括起始值和最终值
IS NULL关键字判断该列的值是否为空值,空值不是空字符串
SELECT 字段 FROM 表名 WHERE 列名 IS [NOT] NULL
SELECT * FROM patient WHERE address IS NOT NULL
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wbdv53sv-1680502580622)(./assets/image-20230402235909456.png)]
NOT 可选参数,表示取反
子查询是一个嵌套在 SELECT、INSERT、UPDATE 或 DELETE 语句或其他子查询中的查询
SELECT …… FROM 表1 WHERE 字段1 比较运算符 (子查询);
SELECT * FROM patient WHERE patientID IN(1,2,3,4,5,9)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drEI5jCV-1680502580623)(./assets/image-20230403000309493.png)]
SELECT * FROM patient WHERE patientID IN(SELECT patientID FROM patient WHERE patient.patientID BETWEEN 5 AND 15)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEpX4G4k-1680502580623)(./assets/image-20230403000418635.png)]
先执行子查询,返回所有来自子查询的结果
再执行外围的父查询,返回查询的最终结果
将子查询和比较运算符联合使用
必须保证子查询返回的值不能多于一个
SELECT …… FROM 表名 WHERE 字段名 IN (子查询);
与in
一样,查询结果有多条使用
获取的值是不包含在查询结果里面的值
SELECT …… FROM 表名 WHERE 字段名 NOT IN (子查询);
DROP TABLE IF EXISTS temp;
CREATE TABLE log (
… … #省略建表语句
) ;
SELECT …… FROM 表名 WHERE EXISTS (子查询);
当一个查询是另一个查询的条件时,称之为子查询
任何允许使用表达式的地方都可以使用子查询
嵌套在父查询SELECT语句的子查询,可包括
SELECT 子句
SELECT (子查询) [AS 列别名] FROM 表名;
FROM 子句
SELECT * FROM (子查询) AS 表别名;
WHERE 子句
GROUP BY 子句
HAVING 子句
通常,将子查询放在比较条件的右边以增加可读性
子查询可以返回单行或多行数据,此时要选择合适的关键字
子查询的返回是单行数据时,比较条件中可以使用比较运算符
子查询的返回是多行数据时,比较条件中需要使用IN或 NOT IN 关键字
如果判断子查询是否有数据返回时,需要使用 EXISTS 或 NOT EXISTS 关键字
只出现在子查询中、而没有出现在父查询中的列不能包含在输出列中
JOIN 按照功能大致分为如下三类
最典型、最常用的连接查询,根据两张表中共同的列进行匹配,两个表存在主外键关系时,通常会使用内连接查询
SELECT …… FROM 表1 INNER JOIN 表2 ON ……
INNER JOIN用来连接两个表
INNER可以省略
ON用来设置两个表之间的关联条件
SELECT * FROM department_checkitem
INNER JOIN department ON department_checkitem.depID=department.depID
INNER JOIN checkitem ON department_checkitem.checkItemID=checkitem.checkItemID
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qptBwjF-1680502580623)(./assets/image-20230403001247130.png)]
特点
SELECT * FROM prescription
LEFT JOIN patient ON prescription.patientID=patient.patientID
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZTVDxLVp-1680502580624)(./assets/image-20230403001525010.png)]
SELECT * FROM prescription
RIGHT JOIN patient ON prescription.patientID=patient.patientID
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9r659cBL-1680502580624)(./assets/image-20230403001641747.png)]
关于存储过程我只能说请看下图,这是阿里巴巴发布的《阿里巴巴Java开发手册(终极版)v1.3版本》
在 MySQL 第七条中强制指出禁止使用存储过程
所以对于存储过程不必深究,做到会写能看懂即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-36sAcKTC-1680502580624)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230329084802.png)]
Stored Procedure
优点
缺点
SQL 最大的缺点还是 SQL 语言本身的局限性 SQL 本身是一种结构化查询语言,我们不应该用存储过程处理复杂的业务逻辑让 SQL 回归它
结构化查询语言
的功用。复杂的业务逻辑,还是交给代码去处理吧
CREATE
[DEFINER = { user | CURRENT_USER }]
# 定义DEFINER默认为当前用户
PROCEDURE 存储过程名
[SQL SECURITY { DEFINER | INVOKER } | …]
# 指定DEFINER或INVOKER权限
BEGIN
…
END
特性 | 说明 |
---|---|
LANGUAGE SQL | 表示存储过程语言,默认SQL |
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA} | 表示存储过程要做的工作类别默认值为CONTAINS SQL |
SQL SECURITY { DEFINER | INVOKER } | 指定存储过程的执行权限默认值是DEFINERDEFINDER:使用创建者的权限INVOKER:用执行者的权限 |
COMMENT ‘string’ | 存储过程的注释信息 |
如果省略 SQL SECURITY 特性,则使用 DEFINER 属性指定调用者,且调用者必须具有 EXECUTE 权限,必须在 mysql.user 表中如果将 SQL SECURITY 特性指定为 INVOKER,则 DEFINER 属性无效
IN:指输入参数
OUT:指输出参数
INOUT:指输入输出参数
如果需要定义多个参数,需要使用
,
进行分隔
CALL 存储过程名([参数1,参数2, …]);
# 根据存储过程的定义包含相应的参数
存储过程调用类似于Java中的方法调用
SHOW PROCEDURE STATUS
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qm2luvDd-1680502580624)(./assets/image-20230403133422488.png)]
SHOW CREATE PROCEDURE 存储过程名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfEqJMLf-1680502580625)(./assets/image-20230403133612810.png)]
ALTER PROCEDURE 存储过程名[特性………]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7x2HRAG-1680502580625)(./assets/image-20230403133809483.png)]
DROP PROCEDURE 存储过程名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MOKUmqzh-1680502580625)(./assets/image-20230403133956314.png)]
与Java语言类似,定义存储过程时可以使用变量
DECLARE 变量名[,变量名...] 数据类型 [DEFAULT 值];
给变量进行赋值
SET 变量名 = 表达式值[,变量名=表达式...] ;
定义存储过程时,所有局部变量的声明一定要放在存储过程体的开始;否则,会提示语法错误
系统变量
@@
开头,形式为@@变量名
用户自定义变量
@
开头,形式为@变量名
演示案例
CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_exam_GetLastExamDateByPatientNameAndDepID`(IN patient_name VARCHAR(50), IN dep_id INT,OUT last_exam_date DATETIME)
BEGIN
#Routine body goes here...
DECLARE patient_id INT; #声明局部变量
SELECT patientID INTO patient_id FROM patient WHERE patientName= patient_name;
SELECT patient_id; #输出病人的ID
SELECT MAX(examDate) INTO last_exam_date FROM prescription WHERE patientID = patient_id AND depID = dep_id;
END
SET @patient_name='夏颖';
SET @dep_id =1;
CALL proc_exam_GetLastExamDateByPatientNameAndDepID(@patient_name, @dep_id, @last);
SELECT @last;
与Java语言的流程控制语句类似,MySQL提供的控制语句
IF 条件 THEN 语句列表
[ELSEIF 条件 THEN 语句列表]
[ELSE 语句列表]
END IF;
根据病人的家庭收入,返还补贴不同比例的医疗费用
- 家庭年收入在5000元以下的返还当年总医疗费用的20%
- 家庭年收入在10000以下的返还当年总医疗费用的15%
- 家庭年收入在30000以下的返还总医疗费用的5%
- 30000元以上或未登记的不享受医疗费用返还
- 输入病人编号和年份,计算该患者当年的应返还的医疗费用
CREATE DEFINER=`root`@`localhost` PROCEDURE `Proc_CH05_4`(IN patient_ID INT ,IN in_year VARCHAR(50),OUT ou_subsidy FLOAT )
BEGIN
DECLARE tital_Cost FLOAT;
DECLARE totial_income FLOAT;
SELECT incomeMoney INTO totial_income FROM income WHERE patientID =patient_ID;
SELECT sum(checkItemCost) INTO tital_Cost FROM prescription
INNER JOIN checkitem ON prescription.checkItemID=checkitem.checkItemID
WHERE patientID=patient_ID AND examDate >= CONCAT(in_year,'-01-01')
AND examDate <= CONCAT(in_year,'-12-31');
IF totial_income>=0 AND totial_income<5000 THEN
SET ou_subsidy =tital_Cost*0.2;
ELSEIF totial_income>=5000 AND totial_income<10000 THEN
SET ou_subsidy =tital_Cost*0.15;
ELSEIF totial_income>=10000 AND totial_income<30000 THEN
SET ou_subsidy =tital_Cost*0.05;
ELSE
SET ou_subsidy =0;
END IF;
END
CASE
WHEN 条件 THEN 语句列表
[WHEN 条件 THEN 语句列表]
[ELSE 语句列表]
END CASE;
CASE 列名
WHEN 条件值 THEN 语句列表
[WHEN 条件值 THEN 语句列表]
[ELSE 语句列表]
END CASE;
使用CASE语句实现返还补贴不同比例的医疗费用
CREATE DEFINER=`root`@`localhost` PROCEDURE `Proc_CH05_5`(IN patient_ID INT ,IN in_year VARCHAR(50),OUT ou_subsidy FLOAT )
BEGIN
DECLARE tital_Cost FLOAT;
DECLARE totial_income FLOAT;
SELECT incomeMoney INTO totial_income FROM income WHERE patientID =patient_ID;
SELECT sum(checkItemCost) INTO tital_Cost FROM prescription
INNER JOIN checkitem ON prescription.checkItemID=checkitem.checkItemID
WHERE patientID=patient_ID AND examDate >= CONCAT(in_year,'-01-01')
AND examDate <= CONCAT(in_year,'-12-31');
CASE
WHEN totial_income>=0 AND totial_income<5000 THEN
SET ou_subsidy =tital_Cost*0.2;
WHEN totial_income>=5000 AND totial_income<10000 THEN
SET ou_subsidy =tital_Cost*0.15;
WHEN totial_income>=10000 AND totial_income<30000 THEN
SET ou_subsidy =tital_Cost*0.05;
WHEN totial_income>=30000 AND totial_income<0 THEN
SET ou_subsidy =0;
END CASE;
END
在某种情况下(例如,做等值判断),使用第二种写法更加简洁但是,因为CASE后面有列名,功能上会有一些限制
[label:] WHILE 条件 DO
语句列表
END WHILE [label]
- 首先判断条件是否成立。如果成立,则执行循环体
- label为标号,用于区分不同的循环,可省略
- 用在begin、repeat、while 或者loop 语句前
假设有测试表test,有Id字段、Val字段
- 根据输入的行数要求,批量插入测试数据
DECLARE rand_val FLOAT;
WHILE rows > 0 DO
SELECT RAND() INTO rand_val;
INSERT INTO test VALUES(NULL, rand_val);
SET rows = rows - 1;
END WHILE;
[label:] LOOP
语句列表
END LOOP [label] ;
不需判断初始条件,直接执行循环体
LEAVE label ;
遇到 LEAVE 语句,退出循环
批量插3个新的检查项目,检查项目名称为胃镜、肠镜和支气管纤维镜,各项检查的价格均为70元
CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_checkitem_insert`( IN checkitems VARCHAR(100))
BEGIN
DECLARE comma_pos INT;
DECLARE current_checkitem VARCHAR(20);
loop_label: LOOP
SET comma_pos = LOCATE(',', checkitems);
SET current_checkitem = SUBSTR(checkitems, 1, comma_pos-1);
IF current_checkitem <> '' THEN
SET checkitems = SUBSTR(checkitems, comma_pos+1);
ELSE
SET current_checkitem = checkitems;
END IF;
INSERT INTO checkitem(checkItemName,checkItemCost) VALUES(current_checkitem,70);
IF comma_pos=0 OR current_checkitem='' THEN
LEAVE loop_label;
# 退出loop_label标识的程序块
END IF;
END LOOP loop_label;
# LOOP循环结束
END
[label:] REPEAT
语句列表
UNTIL 条件
END REPEAT [label]
- 先执行循环操作再判断循环条件
- 与 LOOP 循环语句相比较相同点
- 不需要初始条件直接进入循环体
- 不同点:REPEAT 语句可以设置退出条件
使用REPEAT循环语句编码实现,根据输入的行数要求,向测试表test中批量插入测试数据
CREATE DEFINER=`root`@`localhost` PROCEDURE `Proc_CH05_7`(IN rows INT )
BEGIN
DECLARE rand FLOAT;
REPEAT
SELECT RAND() INTO rand;
INSERT INTO test (val)VALUES(rand);
SET rows = rows -1 ;
UNTIL rows <= 0 END REPEAT;
END
ITERATE label;
- 从当前代码处返回到程序块开始位置,重新执行
- ITERATE关键字可以嵌入到LOOP、WHILE和REPEAT程序块中
输入需增加数据行数,随机产生的测试数据必须大于0.5
CREATE DEFINER=`root`@`localhost` PROCEDURE `Proc_CH05_8`(IN rows INT)
BEGIN
DECLARE rand FLOAT;
random_lbl : REPEAT
SELECT RAND() INTO rand;
IF rand< 0.5 THEN
ITERATE random_lbl;
END IF;
INSERT INTO test (val) VALUES (rand);
SET rows=rows-1;
UNTIL rows<=0 END REPEAT;
END