存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。
一、存储过程语法
DELIMITER //
CREATE PROCEDURE 方法名 (参数类型 参数名 数据类型,...);
BEGIN
过程体(编写方法需要执行的操作);
END;
//
DELIMITER ;
说明:
(1)分隔符->MySQL默认以";"为分隔符,如果没有声明分割符,则编译器会把存储过程当成SQL语句进行处理,因此编译过程会报错,所以要事先用“DELIMITER //”声明当前段分隔符,让编译器把两个"//"之间的内容当做存储过程的代码,不会执行这些代码;“DELIMITER ;”的意为把分隔符还原。
(2)参数->存储过程根据需要,可能会有输入、输出、输入输出参数,如果有多个参数用","分割开。MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT:
IN参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
OUT:该值可在存储过程内部被改变,并可返回
INOUT:调用时指定,并且可被改变和返回。
in:表示输入一个值,你需要一个值,我给你一个值
out:你往外输出一个值,你输出的那个值我就拿一个变量来接收你给我输出的那个值
(3)过程体->过程体的开始与结束使用BEGIN与END进行标识。
二、存储过程的意义
(1)增强SQL语言的功能和灵活性:
存储过程可以用控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。
(2)提升复用程度 :
存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。
(3)较快的执行速度:
存储过程是预编译的。而批处理的SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。
(4)减少网络流量:
针对同一个数据库对象的操作,如果操作的SQL语句写在存储过程,当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大减少网络流量并降低了网络负载
三、调用存储过程
CALL 方法名
四、用户定义变量
(1)用户变量
使用SET或SELECT直接赋值,变量名以 @ 开头.
例如: SET @var=1;
SELECT @var:=5;
SELECT empno,ename INTO @var,@name FROM EMP WHERE empno =7499 ;
可以在一个会话的任何地方声明,用户变量可以作用于当前整个连接,但是当前连接断开后,其所定义的用户变量都会消失称为用户变量。
(2)局部变量
DECLARE 关键字声明的变量,只能在存储过程中使用,称为存储过程变量,
格式:DECLARE varname1[,varname2] …… datatype [DEFAULT VALUE]
例如:
DECLARE var1 INT DEFAULT 0;
DECLARE v1,v2 VARCHAR(20);
SET C= 5; //赋值
SELECT empno,empname INTO var1,v1 FROMemp WHERE empno =7499;
局部变量一般用在sql语句块中,比如存储过程的begin/end。其作用域仅限于该语句块,在该语句
块执行完毕后,局部变量就消失了。
#练习1:编写一个存储过程,要求能够对emp表中指定部门员工人数进行统计,并返回给调用者
SELECT * FROM emp
DELIMITER//
CREATE PROCEDURE statistical_two(IN department INT)
BEGIN
SELECT IFNULL(COUNT(empno),'无员工') FROM EMP GROUP BY deptno
HAVING deptno = department;
END;
//
DELIMITER;
CALL statistical_two(40)
#练习2:编写一个存储过程,要求能够对emp表中的所有员工平均工资进行统计,并返回调用者
DELIMITER//
CREATE PROCEDURE salarynum_one ()
BEGIN
SELECT AVG(sal) FROM emp;
END;
//
DELIMITER;
CALL salarynum_one
-----------------------------------
DELIMITER//
CREATE PROCEDURE salarynum (OUT salary FLOAT)
BEGIN
SELECT AVG(sal)INTO salary FROM emp;
END;
//
DELIMITER;
CALL salarynum(@1);
SELECT @1
/#练习3:编写一个存储过程,要求在执行过程时,输入一个员工的id号,
/#过程能把该员工的所属部门名称和他的直接领导的姓名返回给调用者。#/
DELIMITER //
CREATE PROCEDURE belong_two (IN idnum INT)
BEGIN
SELECT ename,dname FROM emp,dept
WHERE emp.deptno = dept.deptno
AND emp.empno = (SELECT mgr FROM emp WHERE empno = idnum);
END;
//
DELIMITER;
CALL belong_two(7369)
/#练习4:编写一个存储,要求在调用存储时,输入一个员工的id号,该函数能对该id号进行判断,判断其是一个普通员工,还是一个管理人员,如果是一个管理人员,就把他所管理的人数统计出来#/
DELIMITER //
CREATE PROCEDURE Pmanager(IN eid INT)
BEGIN
DECLARE n_work VARCHAR(20);
DECLARE num INT;
SET n_work=(SELECT job FROM emp WHERE empno=eid);
IF (n_work='MANAGER'OR n_work='PRESIDENT') THEN
SELECT COUNT(*) INTO num FROM emp WHERE mgr=eid;
SELECT '是管理人员',num;
ELSE
SELECT'是普通人员';
END IF;
END;
#1. 查询product表,显示销售价格低于4000的商品信息
SELECT * FROM product
WHERE pro_price < 4000
#2. 查询product表,显示销售价格最高的商品的信息
SELECT * FROM product
WHERE pro_price IN (SELECT MAX(pro_price) FROM product)
#3. 查询product表,显示10号供应商所提供的商品信息
SELECT * FROM product
WHERE pro_sup_id = 10
#4. 查询product表,显示10号供应商所提供的商品的平均销售价格
SELECT AVG(pro_price) FROM product
WHERE pro_sup_id = 10
#5. 查询product表,显示每个供应商所提供商品的平均价格,平均价格保留两位小数,按供应商编号降序排列
SELECT CAST(AVG(pro_price) AS DECIMAL(18,2)) FROM product
GROUP BY pro_sup_id
ORDER BY pro_sup_id DESC
#6. 查询supplier表,显示在广东的供应商信息
SELECT * FROM supplier
WHERE sup_loc LIKE '广东%'
#7. 查询salesman表,显示领导编号为空的销售人员信息
SELECT * FROM salesman
WHERE sm_mgr IS NULL
#8. 查询product表和supplier表,显示‘mate7’的供应商信息
SELECT sup_id,sup_name,sup_loc FROM supplier LEFT JOIN product
ON pro_sup_id = sup_id
WHERE pro_name = 'mate7'
#9. 查询salesman表,显示每个销售人员及其领导的姓名 虚表
SELECT a.sm_name salesman,b.sm_name mgr FROM salesman a,salesman b
WHERE a.sm_mgr = b.sm_id
#10. 查询salegrade表,显示2015年1月16日的销售总额
SELECT SUM(sg_grade) FROM salegrade
WHERE sg_date = '2015-01-16'
#11. 查询salegrade表,显示2015年1月16日的销售额最高的销售人员信息(使用分页子查询)
SELECT m.sm_id,m.sm_job,m.sm_mjr,m.sm_name,m.sm_phno,m.sm_sex
FROM salesgrade s,salesman m
WHERE s.sm_id= m.sm_id
AND m.sm_id IN (
SELECT DISTINCT sm_id FROM salesgrade WHERE sg_grade =
(SELECT MAX(sg_grade) FROM salesgrade WHERE sg_date ='2015-1-06')
)
#12. 查询salegrade表,显示2015年1月16日‘iPhone6’的销售数量
SELECT * FROM product
SELECT * FROM salegrade
SELECT * FROM salesman
SELECT * FROM supplier
SELECT SUM(a.sg_grade)/b.pro_price num FROM salegrade a,product b
WHERE a.pro_id = b.pro_id
AND b.pro_name = 'iPhone6'
AND a.sg_date = '2015-01-16'
#13. 查询salegrade表和salesman表,显示‘SMITH’在2015年1月的销售总额
SELECT SUM(a.sg_grade) FROM salegrade a,salesman b
WHERE a.sm_id = b.sm_id
AND b.sm_name = 'SMITH'
AND a.sg_date LIKE '2015-01-%'
#14. 查询product表和supplier表,显示每家供应商的名称,提供的商品数量,未提供商品的供应商也需要显示(数量显示为0)
SELECT * FROM product
SELECT * FROM supplier
SELECT b.sup_name,IFNULL(SUM(a.pro_num),0) FROM product a RIGHT JOIN supplier b
ON a.pro_sup_id = b.sup_id
GROUP BY b.sup_name
#15. 查询salegrade表,product表,显示2015年1月16日各型号商品的销售数量
SELECT * FROM product
SELECT * FROM salegrade
SELECT a.pro_name,SUM(b.sg_grade/a.pro_price) FROM product a,salegrade b
WHERE a.pro_id = b.pro_id
AND b.sg_date = '2015-01-16'
GROUP BY a.pro_name
------------------------------------------------------------------
#创建supplier表
CREATE TABLE supplier (
sup_id INT(2) PRIMARY KEY,
sup_name VARCHAR(20) NOT NULL,
sup_loc VARCHAR(40)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO supplier(sup_id,sup_name,sup_loc)
VALUES (10,'苹果','美国加利福尼亚'),
(20,'华为','广东深圳'),
(30,'小米','北京'),
(40,'魅族','广东珠海'),
(50,'vivo','四川成都'),
(60,'联想','北京'),
(70,'HTC','台湾桃源')
SELECT * FROM supplier
#创建product表
CREATE TABLE product (
PRO_ID INT(4) PRIMARY KEY,
PRO_NAME VARCHAR(14) NOT NULL,
PRO_SUP_ID INT(2),FOREIGN KEY(PRO_SUP_ID) REFERENCES supplier(sup_id),
PRO_NUM INT(4),
PRO_PRICE FLOAT(7,2)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
SELECT * FROM product
INSERT INTO product(PRO_ID,PRO_NAME,PRO_SUP_ID,PRO_NUM,PRO_PRICE)
VALUES (1001,'iPhone6 Plus',10,120,6000.00),
(1002,'iPhone6',10,120,5000.00),
(1003,'mate7',20,100,4500.00),
(1004,'荣耀6 Plus',20,200,1999.00),
(1005,'小米NOTE',30,50,1900.00),
(1006,'荣耀6',20,150,1499.00),
(1007,'iPhone5s',10,150,3500.00),
(1008,'小米4',30,100,1499.00),
(1009,'MX4',40,50,1699.00),
(1010,'MX4 PRO',40,120,2199.00)
#创建salesman表 ENUM('M','F')COLLATE utf8_estonian_ci DEFAULT NULL, DROP TABLE salesman
CREATE TABLE salesman (
sm_id CHAR(8) PRIMARY KEY,
sm_name VARCHAR(20) NOT NULL,
sm_job VARCHAR(14),
sm_mgr CHAR(10),
sm_sex CHAR(1) DEFAULT 'M' CHECK (sm_sex IN ('M','F')),
sm_phno CHAR(11)UNIQUE KEY
)ENGINE=INNODB DEFAULT CHARSET=utf8;
SELECT * FROM salesman
DROP TABLE salesman
INSERT INTO salesman(sm_id,sm_name,sm_job,sm_mgr)
VALUES ('20151051','SMITH','SALESMAN','20141030')
INSERT INTO salesman(sm_id,sm_name,sm_job,sm_mgr,sm_sex,sm_phno)
VALUES ('20151038','SCOTT','SALESMAN','20141030','F','13512345678'),
('20141030','JONES','MANAGER','20141001','M','13612345678'),
('20151041','VICKY','SALESMAN','20151031','F','15812345678'),
('20151031','SWIFT','MANAGER','20141001','M','13912345678'),
('20141001','MILLER','DIRECTOR',NULL,'M','17745678923')
#创建salesgrade 表
CREATE TABLE salegrade (
sm_id INT(4),
pro_id INT(4),
sg_date DATE,
sg_grade INT(7)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
SELECT * FROM salegrade
DELETE FROM salegrade
DROP TABLE salegrade
INSERT INTO salegrade(sm_id,pro_id,sg_date,sg_grade)
VALUES (20151051,1001,'2015/1/16',60000),
(20151051,1002,'2015/1/16',30000),
(20151038,1003,'2015/1/16',13500),
(20151038,1004,'2015/1/16',19990),
(20151038,1006,'2015/1/16',2998),
(20151030,1005,'2015/1/16',1900),
(20151030,1008,'2015/1/16',8994),
(20151011,1001,'2015/1/16',72000),
(20151011,1007,'2015/1/16',70000),
(20151011,1002,'2015/1/16',10000),
(20151035,1009,'2015/1/16',11893),
(20151051,1001,'2015/1/20',60000),
(20151051,1001,'2015/1/20',60000),
(20151051,1002,'2015/1/20',30000),
(20151038,1003,'2015/1/20',13500),
(20151038,1004,'2015/1/20',19990),
(20151038,1006,'2015/1/20',2998),
(20151030,1005,'2015/1/20',1900),
(20151030,1008,'2015/1/20',8994),
(20151011,1001,'2015/1/20',72000),
(20151011,1007,'2015/1/20',70000),
(20151011,1002,'2015/1/20',10000),
(20151035,1009,'2015/1/20',11893)
----------------------------------------------------------------