存储过程是什么:
存储过程就是一组SQL语句
存储过程的语法
delimiter $$
create procedure <存储过程名称>([参数1,参数2,…])
begin
<SQL 语句1>;
<SQL 语句2>;
…
end$$
delimiter;
begin 和end之间的SQL语句就是存储过程的内容,被称为过程体,过程体里可有多条完整的SQL语句,但是每条SQL语句都要以;结尾
delimiter用于定义结束符。通常,SQL语句的默认结束符为“;”,但为了将过程体内部的语句分隔符与SQL本身执行层面的结束符区别开,要先用delimiter关键字暂时将SQL语句的默认结束符改为其他符号,一般改成“。所以后跟了”,表示定义存储过程的语句到此结束。
参数模式有3种,分别如下。
• in:输入的参数。
• out:作为返回值的参数(输出的参数)。
• inout:既可以作为输入参数,也可以作为返回值的参数。
存储过程定义好后,使用call关键字就可以实现调用。
存储过程有如下优点。(1)简化查询语句。将重复性查询语句封装成存储过程,在需要用到的地方直接调用定义好的存储过程,这大大简化了SQL语句,使查询语句更加灵活、易读。(2)提高运行效率。运行查询语句时,数据库是先编译后运行的。而存储过程是一个已经编译好的代码块,直接调用存储过程,其运行效率比普通查询语句高。(3)加强数据安全。通过存储过程能够使没有权限的用户在控制之下,间接地提取数据库中的数据,从而确保数据的安全。(4)易于维护。假设你要开发一个使用数据库的应用程序,你应该将SQL语句写在哪里呢?如果你将SQL语句内嵌在应用程序代码中,那么将使整个程序变得混乱且难以维护。通常情况下,我们应该将SQL语句和应用程序代码分开,将SQL语句存储在所属数据库的存储过程中,并且只在应用程序代码中调用存储过程。这样,数据库专业人员可以随时对存储过程进行修改,而不对应用程序源代码产生影响,更加易于维护。(5)减少网络流量。由于存储过程是一个编译好的代码块,当在其他计算机上调用该存储过程时,网络中传送的将是编译好的代码块,这可以大大减少网络流量并降低网络负载。
缺点。(1)可移植性差。存储过程是存储在特定数据库中的,若将程序移植、关联到其他不同的数据库中,可能会导致存储过程失效或运行出错。(2)调试困难。SQL语句的开发环境不如其他编程语言的开发环境功能全面,存储过程的调试要比一般程序的调试困难。(3)无法处理复杂的业务逻辑。SQL语言有它本身的局限性,因为SQL语言是一种结构化查询语言,只擅长查询数据。对于复杂的业务逻辑,存储过程实现起来比较困难且难以维护
创建表的语法:
create table 表名称(
列名1 数据类型,
列名2 数据类型
);
插入数据的语法规则
insert into table(列名1,列名2,列名3,) values(值1,,..值3);

1) 不带参数的存储过程。定义一个查询所有学生姓名的存储过程并调用
delimiter $$
create procedure student_name()
begin
select 姓名
from 学生表
end$$
delimiter;
调用:
call student_name();
2) 带in参数模式的存储过程。定义一个存储过程查询指定学号的学生姓名
delimiter $$
create procedure get_name(in num varchar(100))
begin
select 姓名
from 学生表
where 学号=num;
end$$
delimiter;
call get_name(‘0001’);
3) 带out参数模式的存储过程。
定义一个存储过程查询指定学号的学生姓名,并将获取的学生姓名赋值给变量并输出。
delimiter $$
create procedure get_name1(in num varchar(100),out st_name varchar(100))
begin
*select 姓名 into st_name*
from 学生表
where 学号=num;
end$$
delimiter;
将查询到的姓名通过into关键字赋值给了变量st_name,在get_name1后面的括号中将变量st_name通过out关键字设置为输出参数。这样,过程体中的查询结果不会直接输出,而是赋值给了变量st_name,作为返回值。
call get_name1(‘0001’,@name);
4) 带inout参数模式的存储过程。
delimiter $$
create procedure get_mull(inout a int)
begin
set a = a*2;
end$$
delimiter;
set @num = 10;
call get_mull(@num);
select @num;

写出SQL的存储过程,
建立一个“职员表”,列名是“姓名”“年龄”和“职位”,
然后向里面插入6条数据,
查询出年龄大于30岁的职员的所有信息。6条数据如表7.7所示。
create table 职员表(
姓名 varchar(20),
年龄 int,
职位 varchar(20)
);
delimiter $$
create procedure get_meg(in num int)
begin
select *
from 职员表
where 年龄>num;
end$$
delimiter;
insert into table 职员表(姓名,年龄,职位) values(‘张三’,23,’职员’);
变量,顾名思义,就是能变化的量。它不是一个特定的值,但是我们可以通过给变量赋值,让它变为确定的值。
数据库中的变量有两种:系统变量和用户自定义变量
系统变量时用于设置数据库行为和方式的参数:(一般设有默认值)
启动数据库占用多大的内存,设置访问权限,日志文件的大小,文件存放位置
用户自定义变量:包括会话变量和局部变量
赋值符号“=”和“:=”有什么区别呢?
因为在MySQL数据库中没有“==”这一比较符号,使用select关键字时,进行等于比较使用的是“=”符号,为了系统可以区分这是赋值还是比较,特意增加了一个变量的赋值符号“:=”。也就是说,使用select关键字赋值,必须使用“:=”,以区分比较符号“=”。
会话变量和局部变量的区别:
(1) 会话变量时在当前会话中起作用的变量,其作用域和声明周期均与当前客户端连接相同;会话变量主要用于在不同SQL语句之间传递数据
会话变量的声明和赋值是同时进行的。
*使用set关键字声明并赋值*
*set @会话变量名=值或表达式;*
使用select关键字声明并赋值
select @会话变量名 := 值或者表达式;
select 值或者表达式 into @会话变量名;
select 字段 into @会话变量名 from …;

(2) 局部变量
*局部变量被放在begin和end之间的语句块中*,其作用域仅限于该语句块内,也就是超过该作用域就不能使用这个局部变量了。
局部变量语法
*declare var_name, type [default value];*
• declare是声明局部变量的关键字。
• var_name是变量的名称,可以同时声明多个变量。
• type是变量的数据类型。
• default value将变量的默认值(初始值)设置为value。若无default,则变量的默认值
为null。
声明局部变量后,还*可以对局部变量重新赋值**,set 局部变量名 = 值或者表达式;*
declare c,d int default 0;
set c = a + b;


面试题:

表7.14所示为“成绩表”,包括“学号”“班级”和“成绩”3列,使用变量计算每个班级的成绩,并进行排名,若成绩一样,则并列排名。
set @rank = 0 ,@class = null, @score = null;
select *, (
case
when @class = 班级 then (case when @score = 成绩 then @rank
else @rank := @rank + 1 end)
else @rank := 1 end
) as 排名
@class := 班级
@score := 成绩
from 成绩表
order by 班级asc,成绩 desc;
更改表中的数据使用关键字update
语法格式:
update 表名称 set 列名称 = 新的值;
在表中添加列的书写方法:
alter table 表名称 add column 列名 数据类型;
将某种数据类型的表达式显示的转换为另一种数据类型cast()函数
用法 cast(字段名 as 转换的类型);
从某日期减去指定的时间间隔后的日期date_sub(date,interval expr type);
select date_sub(‘2018-03-09’,interval 11 hour) as newdate;
计算两个时间的差值:timestampdiff()

函数:


将现有格式转换成想要的日期格式,MySQL的函数date_format(date,format);
date_format()函数来提取出日期中的“年月日”部分
date表示想要转换的日期,format表示目标格式

想从表中“日期”列获取星期六的日期,那么用date_format()函数可以写成如下形式,其中,format的值%w表示用于获取星期几。

面试题:

请统计2017年乘飞机在周末从北京流出的人口数。
select 流出城市,sum(数量) as 流出总人口数
from 各城市人口流动表
where 流出城市 = ‘北京’
and 交通工具 = 3
and year(日期) = “2017”
and (date_format(日期,%w) = 0 or date_format(日期,%w) = 6);

问题:查找当前所有雇员入职以来的薪水涨幅,给出雇员编号及对应的薪水涨幅,并按照薪水涨幅进行升序排列。
当前薪水是“薪水表”中的“结束日期”为“2004-01-01”对应的薪水。
入职薪水是“雇员表”中的“雇佣日期”与“薪水表”中的“起始日期”一致时对应的薪水。
with t1 as
(select 雇员编号,薪水 as 起始薪水
from 雇员表 as a
left join 薪水表 as b
on a.雇员编号= b.雇员编号 and a.雇佣日期 = b. 起始日期),
t2 as
(select 雇员编号,薪水 as 当前薪水
from 薪水表
where 结束日期= “2004-01-01”)
select 雇员编号 ,(当前薪水 – 起始薪水) as 薪水涨幅
from t1 as a
left join t2 as b
on a.雇员编号= b.雇员编号;


“订单信息表”里记录了巴西乘客使用打车软件的信息,包括订单ID、乘客ID、呼叫时间、应答时间、取消时间、完单时间,
(1) 表中的时间是北京时间,巴西时间比中国时间晚11个小时。
(2)“grab-time”(应答时间)列的数据值如果是“1971/1/10:00”,则表示该订单没有司机应答,属于无效订单。
(1) 订单的应答率、完单率分别是多少?
(2) 呼叫应答时长有多久?
(3) 从这一周的数据来看,呼叫量最多的是哪一个小时(当地时间)?呼叫量最少的是哪一个小时(当地时间)?
(4) 第二天继续呼叫的乘客占多大比例?
(5) 如果要对乘客进行分类,你认为需要参考哪些因素?
update 订单信息表 set call_time = cast(call_time as datetime);
update 订单信息表 set grab_time = cast(grab_time as datetime);
update 订单信息表 set cancel_time = cast(cancel_time as datetime);
update 订单信息表 set finish_time = cast(finish_time as datetime);

update 订单信息表 set call_time = date_sub(call_time,interval 11 hour);
update 订单信息表 set grab_time = date_sub(grab_time,interval 11 hour);
update 订单信息表 set cancel_time = date_sub(cancel_time,interval 11 hour);
update 订单信息表 set finish_time = date_sub(finish_time,interval 11 hour);

select sum(
case
when year(grab_time) <> 1970 then 1
else 0)/count(call_time) as 应答率
from 订单信息表;
