记忆------数据库代码块
Posted qingruihappy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记忆------数据库代码块相关的知识,希望对你有一定的参考价值。
数据库代码块
mysql的安装
mysql安装步骤
1、打开下载的mysql安装文件,双击运行mysql-5.5.40-win32.msi。
2、选择安装类型,有"Typical(默认)"、"Complete(完全)"、"Custom(用户自定义)"三个选项,选择"Custom",按"next"键继续。
3、在"Developer Components(开发者部分)"上左键单击,选择"This feature,
and all subfeatures, will be installed on local hard drive.",即"此部分,及下属子部分内容,全部安装在本地硬盘上"。在上面的"MySQL Server(mysql服务器)"、"Client Programs(mysql客户端程序)"、"Documentation(文档)"也如此操作,以保证安装所有文件。点选"Change...",手动指定安装目录。
4、填上安装目录,我的是"E:softwareinstallmysql",也建议不要放在与操作系统同一分区,这样可以防止系统备份还原的时候,数据被清空。按"OK"继续。
确认一下先前的设置,如果有误,按"Back"返回重做。按"Install"开始安装。
5、正在安装中,请稍候,安装完成后会出现成功界面,点击成功"next"之后,出现以下界面。
这里询问是否继续配置MySQL数据的参数,勾选上,然后点击"Finish"
1.1.2、MYSQL的配置
1、安装完成了,出现如下界面将进入mysql配置向导。
2、选择配置方式,"Detailed Configuration(手动精确配置)"、"Standard Configuration(标准配置)",我们选择"Detailed Configuration",方便熟悉配置过程。
3、选择服务器类型,"Developer Machine(开发测试类,mysql占用很少资源)"、"Server Machine(服务器类型,mysql占用较多资源)"、"Dedicated MySQL Server Machine(专门的数据库服务器,mysql占用所有可用资源)"
4、选择mysql数据库的大致用途,"Multifunctional Database(通用多功能型,好)"、"Transactional Database Only(服务器类型,专注于事务处理,一般)"、"Non-Transactional Database Only(非事务处理型,较简单,主要做一些监控、记数用,对MyISAM数据类型的支持仅限于non-transactional),按"Next"继续。
5、选择网站并发连接数,同时连接的数目,"Decision Support(DSS)/OLAP(20个左右)"、"Online Transaction Processing(OLTP)(500个左右)"、"Manual Setting(手动设置,自己输一个数)"。
6、是否启用TCP/IP连接,设定端口,如果不启用,就只能在自己的机器上访问mysql数据库了,在这个页面上,您还可以选择"启用标准模式"(Enable Strict Mode),这样MySQL就不会允许细小的语法错误。如果是新手,建议您取消标准模式以减少麻烦。但熟悉MySQL以后,尽量使用标准模式,因为它可以降低有害数据进入数据库的可能性。按"Next"继续
7、就是对mysql默认数据库语言编码进行设置(重要),一般选UTF-8,按 "Next"继续。
8、选择是否将mysql安装为windows服务,还可以指定Service Name(服务标识名称),是否将mysql的bin目录加入到Windows PATH(加入后,就可以直接使用bin下的文件,而不用指出目录名,比如连接,"mysql.exe -uusername -ppassword;"就可以了,不用指出mysql.exe的完整地址,很方便),我这里全部打上了勾,Service Name不变。按"Next"继续。
9、询问是否要修改默认root用户(超级管理)的密码。"Enable root access from remote machines(是否允许root用户在其它的机器上登陆,如果要安全,就不要勾上,如果要方便,就勾上它)"。最后"Create An Anonymous Account(新建一个匿名用户,匿名用户可以连接数据库,不能操作数据,包括查询)",一般就不用勾了,设置完毕,按"Next"继续。
用户名和密码统一设置成:
用户名:root
用户密码:root
10、确认设置无误,按"Execute"使设置生效,即完成MYSQL的安装和配置。
注意:设置完毕,按"Finish"后有一个比较常见的错误,就是不能"Start service",一般出现在以前有安装mysql的服务器上,解决的办法,先保证以前安装的mysql服务器彻底卸载掉了;不行的话,检查是否按上面一步所说,之前的密码是否有修改,照上面的操作;如果依然不行,将mysql安装目录下的data文件夹备份,然后删除,在安装完成后,将安装生成的 data文件夹删除,备份的data文件夹移回来,再重启mysql服务就可以了,这种情况下,可能需要将数据库检查一下,然后修复一次,防止数据出错。
1.1.3,测试是否安装成功
打开cmd -> 输入 mysql -u root -p 回车 -> 输入密码 回车 C:UsersAPPle>mysql -u root -p Enter password: **** Welcome to the MySQL monitor. Commands end with ; or g. Your MySQL connection id is 2 Server version: 5.5.40 MySQL Community Server (GPL) Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;‘ or ‘h‘ for help. Type ‘c‘ to clear the current input statement. |
mysql的卸载
1.2.1,如何彻底的卸载
如何彻底的删除MySQL数据库:
以下操作以Window7操作系统为例:
1)停止window的MySQL服务。
找到"控制面板"-> "管理工具"-> "服务",停止MySQL后台服务。
2)卸载MySQL安装程序。找到"控制面板"-> "程序和功能",卸载MySQL程序。
3)删除MySQL安装目录下的所有文件。
4)删除c盘ProgramData隐藏目录中关于MySQL的目录。
4.1 打开window系统的"显示隐藏文件"功能,以便查看到系统的所有隐藏文件
4.1 找到ProgramData目录
4.3 删除MySQL目录
mysql数据结构
1.3.1,mysql数据结构图解
先数据库,再表,再有数据 |
数据库管理
1.4.1,查询所有数据库
Show databases;(都有哪些数据库) |
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | -- mysql元数据,基础数据 | mysql | --mysql配置数据库,其中包含用户信息。(用户名和密码,权限管理) | performance_schema | --mysql数据库软件的运行数据,日志信息,性能数据 | test | --测试数据库。空的 +--------------------+ 4 rows in set (0.00 sec) |
1.4.2,创建数据库
Create database day15 Default character set utf8; |
1.4.3,删除数据库
Drop database day15; |
1.4.4,查看默认字符集
Show create database day15; |
1.4.5,修改字符集
alter database day15 default character set gbk; |
表管理
1.5.1,选择数据库
Use day15; |
1.5.2,查看所有表
show tables; |
1.5.3,创建表
create table student( sid int, sname varchar(20), sage int ); |
1.5.4,查看表结构
desc student; |
1.5.5,删除表
drop table student; |
1.5.6,修改表
create table student( sid int, sname varchar(20), sage int, remark varchar(20) ); |
添加字段: alter table student add column sgender varchar(2); |
删除字段: alter table student drop column sgender; |
修改字段类型: alter table student modify column remark varchar(100); |
修改字段名称; alter table student change column sgender gender varchar(2); |
修改表名; alter table student rename to teacher; |
增删改表数据
1.6.1,增删该数据
-- 创建表 CREATE TABLE teacher( id INT, NAME VARCHAR(20) ) -- 查看所有表 SHOW TABLES;
DESC student;
DROP TABLE student;
CREATE TABLE student( id INT, NAME VARCHAR(20), gender VARCHAR(2), age INT )
-- ********一、增删改数据********* --- -- 1.1 增加数据 -- 插入所有字段。一定依次按顺序插入 INSERT INTO student VALUES(1,‘张三‘,‘男‘,20); -- 注意不能少或多字段值 -- INSERT INTO student VALUES(2,‘李四‘,‘女‘); -- 插入部分字段 INSERT INTO student(id,NAME) VALUES(2,‘李四‘); |
-- 1.2 修改数据 -- 修改所有数据(建议少用) UPDATE student SET gender=‘女‘; -- 带条件的修改(推荐使用) UPDATE student SET gender=‘男‘ WHERE id=1; -- 修改id为1的学生,修改性别为男 -- 修改多个字段,注意: SET 字段名=值,字段名=值,.... UPDATE student SET gender=‘男‘,age=30 WHERE id=2; |
-- 1.3 删除数据 -- 删除所有数据(建议少用) DELETE FROM student; -- 带条件的删除(推荐使用) DELETE FROM student WHERE id=2; -- 另一种方式 -- delete from: 可以全表删除 1)可以带条件删除 2)只能删除表的数据,不能删除表的约束 用它删除完数据在插入数据的时候id是从原来删除的id索引值开始的 3)使用delete from删除的数据可以回滚(事务) -- truncate table: 可以全表删除 1)不能带条件删除 2)即可以删除表的数据,也可以删除表的约束 id是从1开始的3)使用truncate table删除的数据不能回滚 TRUNCATE TABLE student; CREATE TABLE test( id INT PRIMARY KEY AUTO_INCREMENT, -- 自增长约束 NAME VARCHAR(20) ) DESC test; -- 1. DELETE FROM test; -- 2 TRUNCATE TABLE test; INSERT INTO test(NAME) VALUES(‘张三‘); INSERT INTO test(NAME) VALUES(‘张三2‘); INSERT INTO test(NAME) VALUES(‘张三3‘);
SELECT * FROM test;
-- truncate table student where id=2; 不能带条件 |
1.7,查询数据(重点)
1.7.1,查询所有列
SELECT * FROM student; |
1.7.2,查询指定列
SELECT id,NAME,gender FROM student; |
1.7.3. 查询时添加常量列
SELECT id AS ‘编号‘,NAME AS ‘姓名‘ FROM student; |
SELECT id,NAME,gender,age,‘java就业班‘ AS ‘年级‘ FROM student; |
1.7.4. 查询时合并列
SELECT id,NAME,(servlet+jsp) AS ‘总成绩‘ FROM student; |
-- 注意:合并列只能合并数值类型的字段 SELECT id,(NAME+servlet) FROM student; |
1.7.5,查询时去除重复记录
-- 需求: 查询学生的性别 男 女 SELECT DISTINCT gender FROM student; -- 另一种语法 SELECT DISTINCT(gender) FROM student; |
1.7.6,条件查询
逻辑条件: and(与) or(或) SELECT * FROM student WHERE id=2 AND NAME=‘李四‘; -- 交集 -- 需求: 查询id为2,或姓名为张三的学生 SELECT * FROM student WHERE id=2 OR NAME=‘张三‘; -- 并集 |
-- 2.7.2 比较条件: > < >= <= = <>(不等于) between and (等价于>= 且 <=) -- 需求: 查询servlet成绩大于70分的学生 SELECT * FROM student WHERE servlet>70;
-- 需求: 查询jsp成绩大于等于75,且小于等于90分的学生 SELECT * FROM student WHERE jsp>=75 AND jsp<=90; -- 另一个语法 SELECT * FROM student WHERE jsp BETWEEN 75 AND 90; -- (包前包后)
SELECT * FROM student WHERE gender<>‘男‘;(不是男) |
-- 2.7.3 判空条件(null 空字符串): is null / is not null / =‘‘ / <>‘‘ -- 需求: 查询地址为空的学生(包括null和空字符串) -- null vs 空字符串 -- null:表示没有值 -- 空字符串:有值的! -- 判断null SELECT * FROM student WHERE address IS NULL ; -- 判断空字符串 SELECT * FROM student WHERE address=‘‘;
SELECT * FROM student WHERE address IS NULL OR address=‘‘; -- (包括null和空字符串)
-- 需求: 查询有地址的学生(不包括null和空字符串) SELECT * FROM student WHERE address IS NOT NULL AND address<>‘‘ |
1.7.7,模糊查询
-- 2.7.4 模糊条件: like -- 通常使用以下替换标记: -- % : 表示任意个字符 -- _ : 表示一个字符 -- 需求: 查询姓‘张‘的学生 SELECT * FROM student WHERE NAME LIKE ‘李%‘;
-- 需求: 查询姓‘李‘,且姓名只有两个字的学生 SELECT * FROM student WHERE NAME LIKE ‘李_‘; |
1.7.7,聚合查询
-- 2.8 聚合查询(使用聚合函数的查询) -- 常用的聚合函数: sum() avg() max() min() count() -- 需求:查询学生的servlet的总成绩 (sum() :求和函数) SELECT SUM(servlet) AS ‘servlet的总成绩‘ FROM student;
-- 需求: 查询学生的servlet的平均分 SELECT AVG(servlet) AS ‘servlet的平均分‘ FROM student;
-- 需求: 查询当前servlet最高分 SELECT MAX(servlet) AS ‘最高分‘ FROM student;
-- 需求: 查询最低分 SELECT MIN(servlet) AS ‘最低分‘ FROM student; -- 需求: 统计当前有多少学生(count(字段)) SELECT COUNT(*) FROM student; SELECT COUNT(id) FROM student; -- 注意:count()函数统计的数量不包含null的数据 -- 使用count统计表的记录数,要使用不包含null值的字段 SELECT COUNT(age) FROM student; SELECT * FROM student; |
1.7.8,分页查询
-- 2.9 分页查询(limit 起始行,查询几行) -- 起始行从0开始 -- 分页:当前页 每页显示多少条 -- 分页查询当前页的数据的sql: SELECT * FROM student LIMIT (当前页-1)*每页显示多少条,每页显示多少条; -- 需求: 查询第1,2条记录(第1页的数据) SELECT * FROM student LIMIT 0,2; -- 查询第3,4条记录(第2页的数据) SELECT * FROM student LIMIT 2,2; -- 查询第5,6条记录(第3页的数据) SELECT * FROM student LIMIT 4,2; -- 查询第7,8条记录 (没有记录不显示) SELECT * FROM student LIMIT 6,2; |
1.7.9,查询排序
-- 2.10 查询排序(order by ) -- 语法 :order by 字段 asc/desc -- asc: 顺序,正序。数值:递增,字母:自然顺序(a-z) -- desc: 倒序,反序。数值:递减,字母:自然反序(z-a)
-- 默认情况下,按照插入记录顺序排序 SELECT * FROM student;
-- 需求: 按照id顺序排序 SELECT * FROM student ORDER BY id ASC; SELECT * FROM student ORDER BY id; -- 默认正序
SELECT * FROM student ORDER BY id DESC;-- 反序
-- 注意:多个排序条件 -- 需求: 按照servlet正序,按照jsp的倒序 SELECT * FROM student ORDER BY servlet ASC,jsp DESC; |
1.7.10,分组查询
-- 2.11 分组查询(group by) -- 需求: 查询男女的人数 -- 预期结果: -- 男 3 --- 女 2 -- 1) 把学生按照性别分组(GROUP BY gender) -- 2) 统计每组的人数(COUNT(*)) SELECT gender,COUNT(*) FROM student GROUP BY gender; |
1.7.11,分组查询后筛选
-- 2.12 分组查询后筛选 -- 需求: 查询总人数大于2的性别 -- 1) 查询男女的人数 -- 2)筛选出人数大于2的记录(having) --- 注意: 分组之前条件使用where关键字,分组之前条件使用having关键字 SELECT gender,COUNT(*) FROM student WHERE GROUP BY gender HAVING COUNT(*)>2; |
1.8,数据约束
1.8.1,默认值
-- 1.1 默认值 CREATE TABLE student( id INT, NAME VARCHAR(20), address VARCHAR(20) DEFAULT ‘广州天河‘ -- 默认值 ) DROP TABLE student; -- 当字段没有插入值的时候,mysql自动给该字段分配默认值 INSERT INTO student(id,NAME) VALUES(1,‘张三‘);
-- 注意:默认值的字段允许为null INSERT INTO student(id,NAME,address) VALUE(2,‘李四‘,NULL); INSERT INTO student(id,NAME,address) VALUE(3,‘王五‘,‘广州番禺‘); SELECT * FROM student; |
作用: 当用户对使用默认值的字段不插入值的时候,就使用默认值。 注意: 1)对默认值字段插入null是可以的。 2)对默认值字段可以插入非null |
1.8.2,非空
-- 1.2 非空 -- 需求: gender字段必须有值(不为null) CREATE TABLE student( id INT, NAME VARCHAR(20), gender VARCHAR(2) NOT NULL -- 非空 ) -- 非空字段必须赋值 INSERT INTO student(id,NAME) VALUES(1,‘李四‘); -- 非空字符不能插入null INSERT INTO student(id,NAME,gender) VALUES(1,‘李四‘,NULL);
SELECT * FROM student; |
作用: 限制字段必须赋值 注意: 1)非空字符必须赋值 2)非空字符不能赋null |
1.8.3,唯一
-- 1.3 唯一 CREATE TABLE student( id INT UNIQUE, -- 唯一 NAME VARCHAR(20) )
INSERT INTO student(id,NAME) VALUES(1,‘zs‘); INSERT INTO student(id,NAME) VALUES(1,‘lisi‘); -- ERROR 1062 (23000): Duplicate entry ‘1‘ for key ‘id‘
INSERT INTO student(id,NAME) VALUES(2,‘lisi‘);
SELECT * FROM student; |
作用: 对字段的值不能重复 注意: 1)唯一字段可以插入null 2)唯一字段可以插入多个null |
1.8.4,主键
-- 1.4 主键(非空+唯一) DROP TABLE student;
CREATE TABLE student( id INT PRIMARY KEY, -- 主键 NAME VARCHAR(20) )
INSERT INTO student(id,NAME) VALUES(1,‘张三‘); INSERT INTO student(id,NAME) VALUES(2,‘张三‘); -- INSERT INTO student(id,NAME) VALUES(1,‘李四‘); -- 违反唯一约束: Duplicate entry ‘1‘ for key ‘PRIMARY‘
-- insert into student(name) value(‘李四‘); -- 违反非空约束: ERROR 1048 (23000): Column ‘id‘ cannot be null |
作用: 非空+唯一 注意: 1)通常情况下,每张表都会设置一个主键字段。用于标记表中的每条记录的唯一性。 2)建议不要选择表的包含业务含义的字段作为主键,建议给每张表独立设计一个非业务含义的 id字段。 |
1.8.5,自增长
-- 1.5 自增长 CREATE TABLE student( id INT(4) ZEROFILL PRIMARY KEY AUTO_INCREMENT, -- 自增长,从0开始 ZEROFILL 零填充 NAME VARCHAR(20) )
-- 自增长字段可以不赋值,自动递增 INSERT INTO student(NAME) VALUES(‘张三‘); INSERT INTO student(NAME) VALUES(‘李四‘); INSERT INTO student(NAME) VALUES(‘王五‘);
SELECT * FROM student; -- 不能影响自增长约束 DELETE FROM student; -- 可以影响自增长约束 TRUNCATE TABLE student; |
1.8.6,外键
1.6 外键约束 -- 员工表 CREATE TABLE employee( id INT PRIMARY KEY, empName VARCHAR(20), deptName VARCHAR(20) -- 部门名称 )
INSERT INTO employee VALUES(1,‘张三‘,‘软件开发部‘); INSERT INTO employee VALUES(2,‘李四‘,‘软件开发部‘); INSERT INTO employee VALUES(3,‘王五‘,‘应用维护部‘);
SELECT * FROM employee;
-- 添加员工,部门名称的数据冗余高 INSERT INTO employee VALUES(4,‘陈六‘,‘软件开发部‘);
-- 解决数据冗余高的问题:给冗余的字段放到一张独立表中 -- 独立设计一张部门表 CREATE TABLE dept( id INT PRIMARY KEY, deptName VARCHAR(20) )
DROP TABLE employee;
-- 修改员工表 CREATE TABLE employee( id INT PRIMARY KEY, empName VARCHAR(20), deptId INT,-- 把部门名称改为部门ID -- 声明一个外键约束 CONSTRAINT emlyee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id) -- 外键名称 外键 参考表(参考字段) ) |
作用:约束两种表的数据
出现两种表的情况: 解决数据冗余高问题: 独立出一张表 例如: 员工表 和 部门表 问题出现:在插入员工表数据的时候,员工表的部门ID字段可以随便插入!!!!!
使用外键约束:约束插入员工表的部门ID字段值
解决办法: 在员工表的部门ID字段添加一个外键约束 |
注意: 1)被约束的表称为副表,约束别人的表称为主表,外键设置在副表上的!!! 2)主表的参考字段通用为主键! 3)添加数据: 先添加主表,再添加副表 4)修改数据: 先修改副表,再修改主表 5)删除数据: 先删除副表,再删除主表 |
1.8.7,级联操作
问题: 当有了外键约束的时候,必须先修改或删除副表中的所有关联数据,才能修改或删除主表!但是,我们希望直接修改或删除主表数据,从而影响副表数据。可以使用级联操作实现!!!
级联修改: ON UPDATE CASCADE 级联删除: ON DELETE CASCADE |
CREATE TABLE employee( id INT PRIMARY KEY, empName VARCHAR(20), deptId INT,-- 把部门名称改为部门ID -- 声明一个外键约束 CONSTRAINT emlyee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id) ON UPDATE CASCADE ON DELETE CASCADE -- ON CASCADE UPDATE :级联修改 -- 外键名称 外键 参考表(参考字段) ) 注意: 级联操作必须在外键基础上使用 |
-- 级联修改(修改) -- 直接修改部门 UPDATE dept SET id=5 WHERE id=4;
-- 级联删除 -- 直接删除部门 DELETE FROM dept WHERE id=1; |
1.9,数据库设计
1.9.1,三大范式
设计原则: 建议设计的表尽量遵守三大范式。
第一范式: 要求表的每个字段必须是不可分割的独立单元 student : name -- 违反第一范式 张小名|狗娃 sutdent : name old_name --符合第一范式 张小名 狗娃
第二范式: 在第一范式的基础上,要求每张表只表达一个意思。表的每个字段都和表的主键有依赖。
employee(员工): 员工编号 员工姓名 部门名称 订单名称 --违反第二范式
员工表:员工编号 员工姓名 部门名称
订单表: 订单编号 订单名称 -- 符合第二范式
第三范式: 在第二范式基础,要求每张表的主键之外的其他字段都只能和主键有直接决定依赖关系。
员工表: 员工编号(主键) 员工姓名 部门编号 部门名 --符合第二范式,违反第三范式 (数据冗余高)
员工表:员工编号(主键) 员工姓名 部门编号 --符合第三范式(降低数据冗余) 部门表:部门编号 部门名
|
1.10,关联查询(多表查询)
1.10.1,交叉连接查询
- 需求:查询员工及其所在部门(显示员工姓名,部门名称) -- 2.1 交叉连接查询(不推荐。产生笛卡尔乘积现象:4 * 4=16,有些是重复记录) SELECT empName,deptName FROM employee,dept;
-- 需求:查询员工及其所在部门(显示员工姓名,部门名称) -- 多表查询规则:1)确定查询哪些表 2)确定哪些哪些字段 3)表与表之间连接条件 (规律:连接条件数量是表数量-1) |
1.10.2,内连接查询:只有满足条件的结果才会显示(使用最频繁)
- 2.2 内连接查询:只有满足条件的结果才会显示(使用最频繁) SELECT empName,deptName -- 2)确定哪些哪些字段 FROM employee,dept -- 1)确定查询哪些表 WHERE employee.deptId=dept.id -- 3)表与表之间连接条件
-- 内连接的另一种语法 SELECT empName,deptName FROM employee INNER JOIN dept ON employee.deptId=dept.id;
-- 使用别名 SELECT e.empName,d.deptName FROM employee e INNER JOIN dept d ON e.deptId=d.id;
-- 需求: 查询每个部门的员工 -- 预期结果: -- 软件开发部 张三 -- 软件开发部 李四 -- 应用维护部 王五 -- 秘书部 陈六 -- 总经办 null |
1.10.3,左右[外]连接查询
左[外]连接查询: 使用左边表的数据去匹配右边表的数据,如果符合连接条件的结果则显示,如果不符合连接条件则显示null -- (注意: 左外连接:左表的数据一定会完成显示!) SELECT d.deptName,e.empName FROM dept d LEFT OUTER JOIN employee e ON d.id=e.deptId;
|
右[外]连接查询: 使用右边表的数据去匹配左边表的数据,如果符合连接条件的结果则显示,如果不符合连接条件则显示null -- (注意: 右外连接:右表的数据一定会完成显示!) SELECT d.deptName,e.empName FROM employee e RIGHT OUTER JOIN dept d ON d.id=e.deptId; |
1.10.4,自连接查询
2.4 自连接查询 -- 需求:查询员工及其上司 -- 预期结果: -- 张三 null -- 李四 张三 -- 王五 李四 -- 陈六 王五 SELECT e.empName,b.empName FROM employee e LEFT OUTER JOIN employee b ON e.bossId=b.id; |
1.11,存储过程
1.11.1,什么是存储过程
存储过程,带有逻辑的sql语句 之前的sql没有条件判断,没有循环 存储过程带上流程控制语句(if while) |
1.11.2,存储过程特点
1)执行效率非常快!存储过程是在数据库的服务器端执行的!!! 2)移植性很差!不同数据库的存储过程是不能移植。 |
1.11.3,存储过程语法
-- 创建存储过程 DELIMITER $ -- 声明存储过程的结束符 CREATE PROCEDURE pro_test() --存储过程名称(参数列表) BEGIN -- 开始 -- 可以写多个sql语句; -- sql语句+流程控制 SELECT * FROM employee; END $ -- 结束 结束符
-- 执行存储过程 CALL pro_test(); -- CALL 存储过程名称(参数); |
参数: IN: 表示输入参数,可以携带数据带存储过程中 OUT: 表示输出参数,可以从存储过程中返回结果 INOUT: 表示输入输出参数,既可以输入功能,也可以输出功能 |
-- 3.1 带有输入参数的存储过程 -- 需求:传入一个员工的id,查询员工信息 DELIMITER $ CREATE PROCEDURE pro_findById(IN eid INT) -- IN: 输入参数 BEGIN SELECT * FROM employee WHERE id=eid; END $
-- 调用 CALL pro_findById(4); |
- 3.2 带有输出参数的存储过程 DELIMITER $ CREATE PROCEDURE pro_testOut(OUT str VARCHAR(20)) -- OUT:输出参数 BEGIN -- 给参数赋值 SET str=‘helljava‘; END $
-- 删除存储过程 DROP PROCEDURE pro_testOut; -- 调用 -- 如何接受返回参数的值?? -- ***mysql的变量****** -- 全局变量(内置变量):mysql数据库内置的变量 (所有连接都起作用) -- 查看所有全局变量: show variables -- 查看某个全局变量: select @@变量名 -- 修改全局变量: set 变量名=新值 -- character_set_client: mysql服务器的接收数据的编码 -- character_set_results:mysql服务器输出数据的编码
-- 会话变量: 只存在于当前客户端与数据库服务器端的一次连接当中。如果连接断开,那么会话变量全部丢失! -- 定义会话变量: set @变量=值 -- 查看会话变量: select @变量
-- 局部变量: 在存储过程中使用的变量就叫局部变量。只要存储过程执行完毕,局部变量就丢失!!
-- 1)定义一个会话变量name, 2)使用name会话变量接收存储过程的返回值 CALL pro_testOut(@NAME); -- 查看变量值 SELECT @NAME; |
-- 3.3 带有输入输出参数的存储过程 DELIMITER $ CREATE PROCEDURE pro_testInOut(INOUT n INT) -- INOUT: 输入输出参数 BEGIN -- 查看变量 SELECT n; SET n =500; END $
-- 调用 SET @n=10;
CALL pro_testInOut(@n);
SELECT @n; |
-- 3.4 带有条件判断的存储过程 -- 需求:输入一个整数,如果1,则返回"星期一",如果2,返回"星期二",如果3,返回"星期三"。其他数字,返回"错误输入"; DELIMITER $ CREATE PROCEDURE pro_testIf(IN num INT,OUT str VARCHAR(20)) BEGIN IF num=1 THEN SET str=‘星期一‘; ELSEIF num=2 THEN SET str=‘星期二‘; ELSEIF num=3 THEN SET str=‘星期三‘; ELSE SET str=‘输入错误‘; END IF; END $
CALL pro_testIf(4,@str);
SELECT @str;
|
-- 3.5 带有循环功能的存储过程 -- 需求: 输入一个整数,求和。例如,输入100,统计1-100的和 DELIMITER $ CREATE PROCEDURE pro_testWhile(IN num INT,OUT result INT) BEGIN -- 定义一个局部变量 DECLARE i INT DEFAULT 1; DECLARE vsum INT DEFAULT 0; WHILE i<=num DO SET vsum = vsum+i; SET i=i+1; END WHILE; SET result=vsum; END $
DROP PROCEDURE pro_testWhile;
CALL pro_testWhile(100,@result);
SELECT @result; |
-- 3.6 使用查询的结果赋值给变量(INTO) DELIMITER $ CREATE PROCEDURE pro_findById2(IN eid INT,OUT vname VARCHAR(20) ) BEGIN SELECT empName INTO vname FROM employee WHERE id=eid; END $
CALL pro_findById2(1,@NAME);
SELECT @NAME; |
练习: 编写一个存储过程 如果学生的英语平均分小于等于70分,则输出‘一般‘ 如果学生的英语平均分大于70分,且小于等于90分,则输出‘良好‘ 如果学生的英语平均分大于90分,则输出‘优秀‘
DELIMITER $ CREATE PROCEDURE pro_testAvg(OUT str VARCHAR(20)) BEGIN -- 定义局部变量,接收平均分 DECLARE savg DOUBLE; -- 计算英语平方分 SELECT AVG(english) INTO savg FROM student2; IF savg<=70 THEN SET str=‘一般‘; ELSEIF savg>70 AND savg<=90 THEN SET str=‘良好‘; ELSE SET str=‘优秀‘; END IF; END $
CALL pro_testAvg(@str);
SELECT @str; |
1.11.4,java调用函数
工具类 * @author AdminTC */ public class JdbcUtil {
private static String driver = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://127.0.0.1:3306/js"; private static String user = "root"; private static String password = "root";
static{ try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
public static Connection getConnection() throws Exception{ return DriverManager.getConnection(url,user,password); }
public static void close(Connection conn) throws Exception{ if(conn != null){ conn.close(); } } public static void close(Statement stmt) throws Exception{ if(stmt != null){ stmt.close(); } } public static void close(ResultSet rs) throws Exception{ if(rs != null){ rs.close(); } } } /** * 演示Java调用Mysql的函数 * @author AdminTC */ public class TestJavaCallMysqlFunc { public static void main(String[] args) throws Exception{ String sql = "{? = call hello(?)}";
Connection conn = JdbcUtil.getConnection(); CallableStatement cstmt = conn.prepareCall(sql);
//第一个输出的?设置类型 cstmt.registerOutParameter(1,Types.VARCHAR);
//第二个输入的?设置值 cstmt.setString(2,"赵君");
//调用函数 cstmt.execute();
//接收返回的值 String value = cstmt.getString(1);
//显示 System.out.println(value);
JdbcUtil.close(cstmt); JdbcUtil.close(conn); |
1.11.5,java调用过程
工具类 * @author AdminTC */ public class JdbcUtil {
private static String driver = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://127.0.0.1:3306/js"; private static String user = "root"; private static String password = "root";
static{ try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
public static Connection getConnection() throws Exception{ return DriverManager.getConnection(url,user,password); }
public static void close(Connection conn) throws Exception{ if(conn != null){ conn.close(); } } public static void close(Statement stmt) throws Exception{ if(stmt != null){ stmt.close(); } } public static void close(ResultSet rs) throws Exception{ if(rs != null){ rs.close(); } } } /** |
/** * 演示Java调用Mysql的过程 * @author AdminTC */ public class TestJavaCallMysqlProc { public static void main(String[] args) throws Exception{ //Java调用过程的语法,这里只有一个?号,它是输出值 String sql = "{call simpleproc(?)}";
Connection conn = JdbcUtil.getConnection(); CallableStatement cstmt = conn.prepareCall(sql);
//这个输出的?设置类型,?号下标从1开始 cstmt.registerOutParameter(1,Types.INTEGER);
//执行过程的调用 cstmt.execute();
//接收过程的返回值 Integer count = cstmt.getInt(1);
//显示 System.out.println("共有" + count + "个用户");
JdbcUtil.close(cstmt); JdbcUtil.close(conn); } } |
1.11.6,总结
这里只演示Java如何调用Mysql的过程和函数,不是讲解过程和函数如何书写,关于过程和函数的讲解,我们会在Oracle中学习
----------------------------------------------------------------------------------过程
#修改mysql语句的结果符为// mysql > delimiter //
#定义一个过程,获取users表总记录数,将10设置到变量count中 create procedure simpleproc(out count int) begin select count(id) into count from users; end //
#修改mysql语句的结果符为; mysql > delimiter ;
#调用过程,将结果覆给变量a,@是定义变量的符号 call simpleproc(@a);
#显示变量a的值 select @a;
//以下是Java调用Mysql的过程 String sql = "{call simpleproc(?)}"; Connection conn = JdbcUtil.getConnection(); CallableStatement cstmt = conn.prepareCall(sql); cstmt.registerOutParameter(1,Types.INTEGER); cstmt.execute(); Integer count = cstmt.getInt(1); System.out.println("共有" + count + "人");
----------------------------------------------------------------------------------函数
#修改mysql语句的结果符为// mysql > delimiter //
#定义一个函数,完成字符串拼接 create function hello( s char(20) ) returns char(50) return concat(‘hello,‘,s,‘!‘); //
#修改mysql语句的结果符为; mysql > delimiter ;
#调用函数 select hello(‘world‘);
//以下是Java调用Mysql的函数 String sql = "{? = call hello(?)}"; Connection conn = JdbcUtil.getConnection(); CallableStatement cstmt = conn.prepareCall(sql); cstmt.registerOutParameter(1,Types.VARCHAR); cstmt.setString(2,"zhaojun"); cstmt.execute(); String value = cstmt.getString(1); System.out.println(value); JdbcUtil.close(cstmt); JdbcUtil.close(conn); |
1.12触发器
1.12.1,案例
当操作了某张表时,希望同时触发一些动作/行为,可以使用触发器完成!!
例如: 当向员工表插入一条记录时,希望同时往日志表插入数据 |
-- 需求: 当向员工表插入一条记录时,希望mysql自动同时往日志表插入数据 -- 创建触发器(添加) CREATE TRIGGER tri_empAdd AFTER INSERT ON employee FOR EACH ROW -- 当往员工表插入一条记录时 INSERT INTO test_log(content) VALUES(‘员工表插入了一条记录‘);
-- 插入数据 INSERT INTO employee(id,empName,deptId) VALUES(7,‘扎古斯‘,1); INSERT INTO employee(id,empName,deptId) VALUES(8,‘扎古斯2‘,1);
-- 创建触发器(修改) CREATE TRIGGER tri_empUpd AFTER UPDATE ON employee FOR EACH ROW -- 当往员工表修改一条记录时 INSERT INTO test_log(content) VALUES(‘员工表修改了一条记录‘);
-- 修改 UPDATE employee SET empName=‘eric‘ WHERE id=7;
-- 创建触发器(删除) CREATE TRIGGER tri_empDel AFTER DELETE ON employee FOR EACH ROW -- 当往员工表删除一条记录时 INSERT INTO test_log(content) VALUES(‘员工表删除了一条记录‘);
-- 删除 DELETE FROM employee WHERE id=7; |
1.13,mysql权限问题
1.13.1,案例
-- ***********五、mysql权限问题**************** -- mysql数据库权限问题:root :拥有所有权限(可以干任何事情) -- 权限账户,只拥有部分权限(CURD)例如,只能操作某个数据库的某张表 -- 如何修改mysql的用户密码? -- password: md5加密函数(单向加密) SELECT PASSWORD(‘root‘); -- *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
-- mysql数据库,用户配置 : user表 USE mysql;
SELECT * FROM USER;
-- 修改密码 UPDATE USER SET PASSWORD=PASSWORD(‘123456‘) WHERE USER=‘root‘;
-- 分配权限账户 GRANT SELECT ON day16.employee TO ‘eric‘@‘localhost‘ IDENTIFIED BY ‘123456‘; GRANT DELETE ON day16.employee TO ‘eric‘@‘localhost‘ IDENTIFIED BY ‘123456‘; |
1.14,mysql的优化
.1.14.1,如何优化
为什么要优化: 随着实际项目的启动,数据库经过一段时间的运行,最初的数据库设置,会与实际数据库运行性能会有一些差异,这时我们 就需要做一个优化调整。
数据库优化这个课题较大,可分为四大类: 》主机性能 》内存使用性能 》网络传输性能 》SQL语句执行性能【软件工程师】
下面列出一些数据库SQL优化方案:
(01)选择最有效率的表名顺序(笔试常考) 数据库的解析器按照从右到左的顺序处理FROM子句中的表名, FROM子句中写在最后的表将被最先处理, 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后, 如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。 例如:查询员工的编号,姓名,工资,工资等级,部门名 select emp.empno,emp.ename,emp.sal,salgrade.grade,dept.dname from salgrade,dept,emp where (emp.deptno = dept.deptno) and (emp.sal between salgrade.losal and salgrade.hisal) 1)如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推 2)如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推
(02)WHERE子句中的连接顺序(笔试常考) 数据库采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。 例如:查询员工的编号,姓名,工资,部门名 select emp.empno,emp.ename,emp.sal,dept.dname from emp,dept where (emp.deptno = dept.deptno) and (emp.sal > 1500)
(03)SELECT子句中避免使用*号 数据库在解析的过程中,会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间 select empno,ename from emp;
(04)用TRUNCATE替代DELETE
(05)尽量多使用COMMIT 因为COMMIT会释放回滚点 (06)用WHERE子句替换HAVING子句 WHERE先执行,HAVING后执行
(07)多使用内部函数提高SQL效率
(08)使用表的别名 salgrade s
(09)使用列的别名 ename e
总之,数据库优化不是一天的课题,你得在长期工作实践中,进行反复测试与总结,希望学员们日后好好领会
|
oracle
2.1,oracle的安装卸载
2.1.1,安装图解
2.1.2,oracle的卸载
用Oracle自带的卸载程序不能从根本上卸载Oracle,从而为下次的安装留下隐患,那么怎么才能完全卸载Oracle呢? 那就是直接注册表清除,步骤如下:
1、 开始->设置->控制面板->管理工具->服务 停止所有Oracle服务。
2、 开始->程序->Oracle - OraDb11g_home1->Oracle安装产品-> Universal Installer 卸装所有Oracle产品,但Universal Installer本身不能被删除[如果第二步执行失败,跳到第三步,大部份第二步是失败的]
3、 运行regedit,选择HKEY_LOCAL_MACHINESOFTWAREORACLE,按del键删除这个入口。
4、 运行regedit,删除以下这三个位置中的所有Oracle入口。 HKEY_LOCAL_MACHINESYSTEMControlSet001Services【下】所有Oracle删除 HKEY_LOCAL_MACHINESYSTEMControlSet002Services【下】所有Oracle删除 HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices【下】所有Oracle删除
5、 运行regedit, HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesEventlogApplication【下】所有Oracle删除, 删除所有Oracle入口。
6、 开始->设置->控制面板->系统->高级->环境变量 删除环境变量CLASSPATH和PATH中有关Oracle的设定
7、 从桌面上、STARTUP(启动)组、程序菜单中,删除所有有关Oracle的组和图标
8、 删除e:/oracleDB目录
9、 【重新启动计算机】,重起后才能完全删除Oracle所在目录
10、 删除与Oracle有关的文件,选择Oracle所在的缺省目录C:Oracle,删除这个入 口目录及所有子目录,并从Windows目录(一般为C:WINDOWS)下删除oralce文件等等。
11、 在运行框中输入"win.ini",回车。WIN.INI文件中若有[ORACLE]的标记段,删除该段
12、 【如有必要】,删除所有Oracle相关的ODBC的DSN
13、 到事件查看器中,删除Oracle相关的日志
说明: 如果有个别DLL文件无法删除的情况,则不用理会,重新启动,开始新的安装, 安装时,选择一个新的目录,则,安装完毕并重新启动后,老的目录及文件就可以删除掉了 |
2.2,oracle的初始命令
2.2.1,超级管理员登录
sqlplus / as sysdba |
2.2.2,解锁scott用户并设置密码tiger
以sys超级用户名,dba角色,即超级管理员身份解锁scott方案/用户,并为scott设置一个密码为tiger 解锁用户:alter user scott/hr account unlock; 设置密码:alter user scott/hr identified by tiger/lion; |
2.2.3,以后登录方式
方式一:sqlplus scott/tiger |
方式二:sqlplus |
2.3,oracleSQL和oracle的关系
2.3.1,QL92/【99】标准的四大分类
(A)DML(数据操纵语言):select,insert,update,delete (B)DDL(数据定义语言):create table,alter table,drop table,truncate table 。。。 (C)DCL(数据控制语言):grant 权限 to scott,revoke 权限 from scott 。。。 (D)TCL(事务控制语言):commit,rollback,rollback to savepoint 。。。 |
2.3.2,oracleSQL与SQL92/99的关系
SQL92/99标准,访问任何关系型数据库的标准 oracleSQL语言,只访问Oracle数据库服务器的专用语言 |
2.3.3,Java技术和oracleSQL的关系
JDBC-->使用OracleSQL语法-->Oracle服务器--->orcl数据库-->表-->记录 Hibernate-->使用OracleSQL语法-->Oracle服务器 MyBatis-->使用OracleSQL语法-->Oracle服务器 |
2.4, select
2.4.1,基本sql命令(select)
使用password命令,为scott用户名修改新密码,以字母开头,但提倡使用tiger password 旧口令:tiger 新口令:abc123 再次输入新口令:abc123
退出sqlplus工具 exit
查询当前用户是谁 show user;
查询scott用户下的所有对象,使用tab表,tab表每个用户都有 select * from tab;
设置显示的列宽(字符型varchar2、日期型date),10个宽度位,a表示字符型,大小写均可 column ename format a12; column hiredate format a10;
设置显示的列宽(数值型number),9表示数字型,一个9表示一个数字位,四个9表示四个数字位,只能用9 column empno format 9999; column mgr format 9999; column sal format 9999; column comm format 9999; column deptno format 9999;
设置一页显示80个条记录的高度 set pagesize 80;
使用/杠,执行最近一次的SQL语句 /
清屏,属于SQL*PLUS工具中的命令 host cls;
查询emp表的结构 desc emp;
查询emp表的所有内容,*号表示通配符,表示该表中的所有字段,但*号不能和具体字段一起使用 select * from emp; 或 select empno,ename,sal,deptno from emp;
查询emp表的员工编号,姓名,工资,部门号,列名,大小写不敏感,但提倡大写 select empno "编号",ename "姓名",sal "工资",deptNO "部门号" FROM Emp;
查询emp表的不重复的工作 select distinct job from emp;
查询员工的编号,姓名,月薪,年薪(月薪*12) select empno,ename,sal,sal*12 "年薪" from emp;
查询员工的编号,姓名,入职时间,月薪,年薪,年收入(年薪+奖金) select empno "编号",ename"姓名",hiredate "入职时间",sal "月薪",sal*12 "年薪",sal*12+comm "年收入" from emp; 如果结果为null,在sqlplus客户端工具中,是不显示null这个值的
解决null的问题,使用NVL()函数,NVL(a,b):如果a是NULL,用b替代;如果a是非NULL,就不用b替代,直接返回a的值 select NVL(null,10) from emp;结果有14行记录 select NVL(null,10) from dual;结果有1行记录 select empno "编号",ename"姓名",hiredate "入职时间",sal "月薪",sal*12 "年薪",sal*12+NVL(comm,0) "年收入" from emp; 注意:null与具体数字运算时,结果为null
使用列别名,查询员工的编号,姓名,月薪,年薪,年收入(年薪+奖金),AS大小写都可且可以省略AS,别名用双引号 select empno AS "编号",ename as "姓名",sal "月薪" from emp; 或 select empno AS 编号,ename as 姓名,sal 月薪 from emp; 区别 select empno AS "编号",ename as 姓名,sal "月 薪" from emp; 不加双引号的别名不能有空格;加了双引号的别名可以有空格 要加只能加双引号,不能加单引号,因为在oracle中单引号表示字符串类型或者是日期类型 列名不能使用单引号,因为oracle认为单引号是字符串型或日期型
使用dual哑表或者伪表,使用字符串连接符号||,输出"hello world",在oracle中from是必须写的 select ‘hello‘ || ‘ world‘ "结果" from dual;
使用sysdate,显示系统当前时间,在默认情况下,oracle只显示日期,而不显示时间,格式:26-4月-15 select sysdate from dual;
使用字符串连接符号||,显示如下格式信息:****的薪水是****美元 select ename || ‘的薪水是‘ || sal || ‘美元‘ from emp;
使用spool命令,保存SQL语句到硬盘文件e:/oracle-day01.sql,并创建sql文件 spool e:/oracle-day01.sql;
使用spool off命令,保存SQL语句到硬盘文件e:/oracle-day01.sql,并创建sql文件,结束语句 spool off;和上面的是一起用的
使用@命令,将硬盘文件e:/crm.sql,读到orcl实例中,并执行文件中的sql语句 @ e:/crm.sql;
使用--符号,设置单行注释 --select * from emp; |
2.4.2,准备工作
格式化显示出来的页面 col empno for 9999; col ename for a10; col job for a10; col mgr for 9999; col hiredate for a12; col sal for 9999; col comm for 9999; col deptno for 99; set pagesize 20; col tname for a20; set pagesize 80; |
2.4.3,SQL语句的特点
1)是SQL92/99的ANSI官方标准,只要按照该标准来写,在任何的关系型数据库中都可以直接执行 2)SQL语句的关健字不能简写,例如:select,where,from 3)大小写不敏感,提倡大写 4)能够对表数据进行增删改查操作 5)必须以分号结束 6)通常称做语句 |
2.4.4,SQLPLUS命令的特点
1)是oracle自带的一款工具,在该工具中执行的命令叫SQLPLUS命令 2)SQLPLUS工具的命令中的关健字可以简写,也可以不简写,例如:col ename for a10; 3)大小写不敏感,提倡大写 4)不能够对表数据进行增删改查操作,只能完成显示格式控制,例如:设置显示列宽,清屏,记录执行结果 5)可以不用分号结束,也可以用分号结束,个人提倡不管SQL或SQLPLUS,都以分号结束 6)通常称做命令,是SQLPLUS工具中的命令 注意:SQLPLUS命令是SQLPLUS工具中特有的语句 |
2.5, where
2.5.1,基本sql语句where
查询emp表中20号部门的员工信息 select * from emp where deptno = 20;
查询姓名是SMITH的员工,字符串使用‘‘,内容大小写敏感 select * from emp where ename = ‘SMITH‘; 总结:你所学过的技术中,哪些是大小写敏感,哪些是大小写不敏感
查询1980年12月17日入职的员工,注意oracle默认日期格式(DD-MON-RR表示2位的年份) select * from emp where hiredate = ‘17-12月-80‘;
查询工资大于1500的员工 select * from emp where sal > 1500;
查询工资不等于1500的员工【!=或<>】 select * from emp where sal <> 1500;
查询薪水在1300到1600之间的员工,包括1300和1600 select * from emp where (sal>=1300) and (sal<=1600); 或 select * from emp where sal between 1300 and 1600;
查询薪水不在1300到1600之间的员工,不包括1300和1600 select * from emp where sal NOT between 1300 and 1600;
查询入职时间在"1981-2月-20"到"1982-1月-23"之间的员工 select * from emp where hiredate between ‘20-2月-81‘ and ‘23-1月-82‘; 注意: 1)对于数值型,小数值在前,大数值在后 2)对于日期型,年长值在前,年小值在后
查询20号或30号部门的员工,例如:根据ID号,选中的员工,批量删除 select * from emp where (deptno=20) or (deptno=30); 或 select * from emp where deptno in (30,20);
查询不是20号或30号部门的员工 select * from emp where deptno NOT in (30,20);
查询姓名以大写字母S开头的员工,使用%表示0个,1个或多个字符 select * from emp where ename like ‘S‘; 等价 select * from emp where ename = ‘S‘; select * from emp where ename like ‘S%‘;
注意: 凡是精确查询用=符号 凡是不精确查询用like符号,我们通常叫模糊查询
查询姓名以大写字母N结束的员工 select * from emp where ename like ‘%N‘;
查询姓名第一个字母是T,最后一个字母是R的员工 select * from emp where ename like ‘T%R‘;
查询姓名是4个字符的员工,且第二个字符是I,使用_只能表示1个字符,不能表示0个或多个字符 select * from emp where ename like ‘_I__‘;
插入一条姓名为‘T_IM‘的员工,薪水1200 insert into emp(empno,ename) values(1111,‘T_IM‘);
查询员工姓名中含有‘_‘的员工,使用转义符,让其后的字符回归本来意思【like ‘%\\_%‘ escape ‘‘】 select * from emp where ename like ‘%\\_%‘ escape ‘‘;
插入一个姓名叫‘的员工 insert into emp(empno,ename) values(2222,‘‘‘‘);
插入一个姓名叫‘‘的员工 insert into emp(empno,ename) values(2222,‘‘‘‘‘‘);
查询所有员工信息,使用%或%% select * from emp; select * from emp where ename like ‘%‘; select * from emp where ename like ‘%_%‘;
查询佣金为null的员工 select * from emp where comm is null; 注意:null不能参数=运算 null能参数number/date/varchar2类型运算
查询佣金为非null的员工 select * from emp where comm is not null;
查询无佣金且工资大于1500的员工 select * from emp where (comm is null) and (sal>1500);
查询工资是1500或3000或5000的员工 select * from emp where sal in (4000,10000,1500,3,300,3000,5000);
查询职位是"MANAGER"或职位不是"ANALYST"的员工(方式一,使用!=或<>) select * from emp where (job=‘MANAGER‘) or (job<>‘ANALYST‘);
查询职位是"MANAGER"或职位不是"ANALYST"的员工(方式二,使用not) select * from emp where (job=‘MANAGER‘) or (not(job=‘ANALYST‘)); |
2.6,order by
2.6.1,案例
查询员工信息(编号,姓名,月薪,年薪),按月薪升序排序,默认升序,如果月薪相同,按oracle内置的校验规则排序 select empno,ename,sal,sal*12 from emp order by sal asc;
查询员工信息(编号,姓名,月薪,年薪),按月薪降序排序 select empno,ename,sal,sal*12 from emp order by sal desc;
查询员工信息,按入职日期降序排序,使用列名 select empno,ename,sal,hiredate,sal*12 "年薪" from emp order by hiredate desc;
order by后面可以跟列名、别名、表达式、列号(从1开始,在select子句中的列号) 列名: select empno,ename,sal,hiredate,sal*12 "年薪" from emp order by hiredate desc;
别名: select empno,ename,sal,hiredate,sal*12 "年薪" from emp order by "年薪" desc;
表达式: select empno,ename,sal,hiredate,sal*12 "年薪" from emp order by sal*12 desc;
列号,从1开始: select empno,ename,sal,hiredate,sal*12 "年薪" from emp order by 5 desc;
查询员工信息,按佣金升序或降序排列,null值看成最大值 select * from emp order by comm desc;
查询员工信息,对有佣金的员工,按佣金降序排列,当order by 和 where 同时出现时,order by 在最后 select * from emp where comm is not null order by comm desc;
查询员工信息,按工资降序排列,相同工资的员工再按入职时间降序排列 select * from emp order by sal desc,hiredate desc;
select * from emp order by sal desc,hiredate asc; 注意:只有当sal相同的情况下,hiredate排序才有作用
查询20号部门,且工资大于1500,按入职时间降序排列 select * from emp where (deptno=20) and (sal>1500) order by hiredate desc;
select * from emp where deptno in (10,20,30,50,‘a‘); |
2.7,单行函数
2.7.1,案例
单行函数:只有一个参数输入,只有一个结果输出 多行函数或分组函数:可有多个参数输入,只有一个结果输出
测试lower/upper/initcap函数,使用dual哑表 select lower(‘www.BAIdu.COM‘) from dual; select upper(‘www.BAIdu.COM‘) from dual; select initcap(‘www.BAIdu.COM‘) from dual;
测试concat/substr函数,从1开始,表示字符,不论中英文 select concat(‘hello‘,‘你好‘) from dual;正确 select concat(‘hello‘,‘你好‘,‘世界‘) from dual;错误 select ‘hello‘ || ‘你好‘ || ‘世界‘ from dual;正确 select concat(‘hello‘,concat(‘你好‘,‘世界‘)) from dual;正确 select substr(‘hello你好‘,5,3) from dual; 5表示从第几个字符开始算,第一个字符为1,中英文统一处理 3表示连续取几个字符
测试length/lengthb函数,编码方式为UTF8/GBK(赵君),一个中文占3/2个字节长度,一个英文一个字节 select length(‘hello你好‘) from dual; select lengthb(‘hello你好‘) from dual;
测试instr/lpad/rpad函数,从左向右找第一次出现的位置,从1开始 select instr(‘helloworld‘,‘o‘) from dual; 注意:找不到返回0 大小写敏感 select LPAD(‘hello‘,10,‘#‘) from dual; select RPAD(‘hello‘,10,‘#‘) from dual;
测试trim/replace函数 select trim(‘ ‘ from ‘ he ll ‘) from dual; select replace(‘hello‘,‘l‘,‘L‘) from dual;
测试round/trunc/mod函数作用于数值型 select round(3.1415,3) from dual; select trunc(3.1415,3) from dual; select mod(10,3) from dual;
当前日期:sysdate = 26-4月-15
测试round作用于日期型(month) select round(sysdate,‘month‘) from dual;
测试round作用于日期型(year) select round(sysdate,‘year‘) from dual;
测试trunc作用于日期型(month) select trunc(sysdate,‘month‘) from dual;
测试trunc作用于日期型(year) select trunc(sysdate,‘year‘) from dual;
显示昨天,今天,明天的日期,日期类型 +- 数值 = 日期类型 select sysdate-1 "昨天",sysdate "今天",sysdate+1 "明天" from dual;
以年和月形式显示员工近似工龄,日期-日期=数值,假设:一年以365天计算,一月以30天计算 select ename "姓名",round(sysdate-hiredate,0)/365 "天数" from emp;
使用months_between函数,精确计算到年底还有多少个月 select months_between(‘31-12月-15‘,sysdate) from dual;
使用months_between函数,以精确月形式显示员工工龄 select ename "姓名",months_between(sysdate,hiredate) "精确月工龄" from emp;
测试add_months函数,下个月今天是多少号 select add_months(sysdate,1) from dual;
测试add_months函数,上个月今天是多少号 select add_months(sysdate,-1) from dual;
测试next_day函数,从今天开始算,下一个星期三是多少号【中文平台】 select next_day(sysdate,‘星期三‘) from dual;
测试next_day函数,从今天开始算,下下一个星期三是多少号【中文平台】 select next_day(next_day(sysdate,‘星期三‘),‘星期三‘) from dual;
测试next_day函数,从今天开始算,下一个星期三的下一个星期日是多少号【中文平台】 select next_day(next_day(sysdate,‘星期三‘),‘星期日‘) from dual;
测试last_day函数,本月最后一天是多少号 select last_day(sysdate) from dual;
测试last_day函数,本月倒数第二天是多少号 select last_day(sysdate)-1 from dual;
测试last_day函数,下一个月最后一天是多少号 select last_day(add_months(sysdate,1)) from dual;
测试last_day函数,上一个月最后一天是多少号 select last_day(add_months(sysdate,-1)) from dual;
注意: 1)日期-日期=天数 2)日期+-天数=日期 |
2.8,三种数据类型之间的转换
2.8.1,案例
oracle中三大类型与隐式数据类型转换 (1)varchar2变长/char定长-->number,例如:‘123‘->123 (2)varchar2/char-->date,例如:‘25-4月-15‘->‘25-4月-15‘ (3)number---->varchar2/char,例如:123->‘123‘ (4)date------>varchar2/char,例如:‘25-4月-15‘->‘25-4月-15‘
oracle如何隐式转换: 1)=号二边的类型是否相同 2)如果=号二边的类型不同,尝试的去做转换 3)在转换时,要确保合法合理,否则转换会失败,例如:12月不会有32天,一年中不会有13月
查询1980年12月17日入职的员工(方式一:日期隐示式转换) select * from emp where hiredate = ‘17-12月-80‘;
使用to_char(日期,‘格"常量"式‘)函数将日期转成字符串,显示如下格式:2015 年 04 月 25 日 星期六 select to_char(sysdate,‘yyyy" 年 "mm" 月 "dd" 日 "day‘) from dual;
使用to_char(日期,‘格式‘)函数将日期转成字符串,显示如格式:2015-04-25今天是星期六 15:15:15 select to_char(sysdate,‘yyyy-mm-dd"今天是"day hh24:mi:ss‘) from dual; 或 select to_char(sysdate,‘yyyy-mm-dd"今天是"day HH12:MI:SS AM‘) from dual;
使用to_char(数值,‘格式‘)函数将数值转成字符串,显示如下格式:$1,234 select to_char(1234,‘$9,999‘) from dual;
使用to_char(数值,‘格式‘)函数将数值转成字符串,显示如下格式:¥1,234select to_char(1234,‘$9,999‘) from dual; select to_char(1234,‘L9,999‘) from dual;
使用to_date(‘字符串‘,‘格式‘)函数,查询1980年12月17日入职的员工(方式二:日期显式转换) select * from emp where hiredate = to_date(‘1980年12月17日‘,‘yyyy"年"mm"月"dd"日"‘); 或 select * from emp where hiredate = to_date(‘1980#12#17‘,‘yyyy"#"mm"#"dd‘); 或 select * from emp where hiredate = to_date(‘1980-12-17‘,‘yyyy-mm-dd‘);
使用to_number(‘字符串‘)函数将字符串‘123‘转成数字123 select to_number(‘123‘) from dual; 注意: select ‘123‘ + 123 from dual;246 select ‘123‘ || 123 from dual;123123 使用NVL(a,b)通用函数,统计员工年收入,NVL()作用于任何类型,即(number/varchar2/date) 通用函数:参数类型可以是number或varchar2或date类型 select ename,sal*12+NVL(comm,0) from emp;
使用NVL2(a,b,c)通用函数,如果a不为NULL,取b值,否则取c值,统计员工年收入 select ename,sal*12+NVL2(comm,comm,0) from emp;
使用NULLIF(a,b)通用函数,在类型一致的情况下,如果a与b相同,返回NULL,否则返回a,比较10和10.0是否相同 select NULLIF(10,‘10‘) from dual;
使用SQL99标准通用语法中的case表达式,将职位是分析员的,工资+1000;职位是经理的,工资+800;职位是其它的,工资+400 case 字段 when 条件1 then 表达式1 when 条件2 then 表达式2 else 表达式n end 课后请参考<MySQL5.X的手册>-12.2这个章节 select ename "姓名",job "职位",sal "涨前工资", case job when ‘ANALYST‘ then sal+1000 when ‘MANAGER‘ then sal+800 else sal+400 end "涨后工资" from emp;
使用oracle专用语法中的decode()函数,职位是分析员的,工资+1000;职位是经理的,工资+800;职位是其它的,工资+400 decode(字段,条件1,表达式1,条件2,表达式2,...表达式n) select ename "姓名",job "职位",sal "涨前工资", decode(job,‘ANALYST‘,sal+1000,‘MANAGER‘,sal+800,sal+400) "涨后工资" from emp;
单引号出现的地方如下: 1)字符串,例如:‘hello‘ 2)日期型,例如:‘17-12月-80‘ 3)to_char/to_date(日期,‘YYYY-MM-DD HH24:MI:SS‘)
双引号出现的地方如下: 1)列别名,例如:select ename "姓 名" from emp 2)to_char/to_date(日期,‘YYYY"年"MM"月"DD"日" HH24:MI:SS‘)‘‘号中的英文字符大小写不敏感 |
2.9,多行函数
2.9.1案例
函数:oracle服务器先事写好的一段具有一定功能的程序片段,内置于oracle服务器,供用户调用 单行函数:输入一个参数,输出一个结果,例如:upper(‘baidu.com‘)->BAIDU.COM 多行函数:输入多个参数,或者是内部扫描多次,输出一个结果,例如:count(*)->14
统计emp表中员工总人数 select count(*) from emp; *号适用于表字段较少的情况下,如果字段较多,扫描多间多,效率低,项目中提倡使用某一个非null唯一的字段,通常是主键
统计公司有多少个不重复的部门 select count(distinct deptno) from emp;
统计有佣金的员工人数 select count(comm) from emp; 注意:今天讲的这些多个行函数,不统计NULL值
员工总工资,平均工资,四舍五入,保留小数点后0位 select sum(sal) "总工资",round(avg(sal),0) "平均工资" from emp;
查询员工表中最高工资,最低工资 select max(sal) "最高工资",min(sal) "最低工资" from emp;
入职最早,入职最晚员工 select max(hiredate) "最晚入职时间",min(hiredate) "最早入职时间" from emp;
多行函数:count/sum/avg/max/min
按部门求出该部门平均工资,且平均工资取整数,采用截断 select deptno "部门编号",trunc(avg(sal),0) "部门平均工资" from emp group by deptno;
(继续)查询部门平均工资大于2000元的部门 select deptno "部门编号",trunc(avg(sal),0) "部门平均工资" from emp group by deptno having trunc(avg(sal),0) > 2000;
(继续)按部门平均工资降序排列 select deptno "部门编号",trunc(avg(sal),0) "部门平均工资" from emp group by deptno having trunc(avg(sal),0) > 2000 order by 2 desc;
除10号部门外,查询部门平均工资大于2000元的部门,方式一【having deptno<>10】 select deptno,avg(sal) from emp group by deptno having deptno<>10;
除10号部门外,查询部门平均工资大于2000元的部门,方式二【where deptno<>10】 select deptno,avg(sal) from emp where deptno<>10 group by deptno; 提倡
显示部门平均工资的最大值 select max(avg(sal)) "部门平均工资的最大值" from emp group by deptno;
思考:显示部门平均工资的最大值和该部门编号? select max(avg(sal)) "部门平均工资的最大值",deptno "部门编号" from emp group by deptno; 错误
group by 子句的细节: 1)在select子句中出现的非多行函数的所有列,【必须】出现在group by子句中 2)在group by子句中出现的所有列,【可出现可不现】在select子句中
where和having的区别: where: 1)行过滤器 2)针对原始的记录 3)跟在from后面 4)where可省 5)先执行
having: 1)组过滤器 2)针对分组后的记录 3)跟在group by后面 4)having可省 5)后执行
oracle中综合语法: 1)select子句-----必须 2)from子句-------必须,不知写什么表了,就写dual 3)where子句------可选 4)group by子句---可选 5)having子句-----可选 6)order by 子句--可选,如果出现列名,别名,表达式,字段 |
2.10,多表连接查询
2.10.1,案例
员工表emp和部门表dept的笛卡尔集(笛卡尔集表=列数之和,行数之积,笛卡尔集表内中有些数据是不符合要求的) select emp.ename,dept.dname from emp,dept;
使用等值连接/内连接(只能使用=号),显示员工的编号,姓名,部门名,使用表别名简化 select emp.empno,emp.ename,dept.dname,dept.deptno from emp,dept where emp.deptno = dept.deptno;
使用非等值连接(不能使用=号,其它符号可以,例如:>=,<=,<>,betwen and等),显示员工的编号,姓名,月薪,工资级别 select e.empno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal;
内连接查询:只能查询出符合条件的记录 外连接查询:既能查询出符合条件的记录,也能根据一方强行将另一个方查询出来
使用外连接,按部门10,20,30,40号,统计各部门员工人数,要求显示部门号,部门名,人数 部门号 部门名 人数 10 ACCOUNTING 3 20 RESEARCH 5 30 SALES 6 40 OPERATIONS 0
等值连接/非等值连接/内连接:只会查询出多张表中,根据某个字段匹配,符合条件的记录,不符合条件的记录是不会存在的
左外连接[是oracle专用的,不是SQL99规则]: select dept.deptno "部门号",dept.dname "部门名",count(emp.empno) "人数" from dept,emp where dept.deptno = emp.deptno(+) group by dept.deptno,dept.dname;
右外连接: select dept.deptno "部门号",dept.dname "部门名",count(emp.empno) "人数" from dept,emp where emp.deptno(+) = dept.deptno group by dept.deptno,dept.dname;
使用左外连接,按部门10,20,30,40号,统计各部门员工人数,要求显示部门号,部门名,人数,且按人数降序排列 select dept.deptno "部门号",dept.dname "部门名",count(emp.empno) "人数" from dept,emp where dept.deptno = emp.deptno(+) group by dept.deptno,dept.dname order by 3 desc;
使用自连接,显示"SMITH的上级是FORD"这种格式 select users.ename || ‘的上级是‘ ||boss.ename from emp users,emp boss where users.mgr = boss.empno; 只有13条记录,不含有KING
基于上述问题,将KING的上级是""显示出来 select users.ename || ‘的上级是‘ ||boss.ename from emp users,emp boss where users.mgr = boss.empno(+); 14条记录 注意:自连接也用到内连接和外连接 |
2.11,子查询
2.11.1,案例
子查询的作用:查询条件未知的事物
查询条件已知的问题:例如:查询工资为800的员工信息 查询条件未知的问题:例如:查询工资为20号部门平均工资的员工信息 一个条件未知的问题,可以分解为多个条件已知的问题
查询工资比WARD高的员工信息 第一:查询WARD的工资? select sal from emp where ename = ‘WARD‘;
第二:查询工资比1250高的员工信息? select * from emp where sal > 1250;
子查询: select * from emp where sal > ( select sal from emp where ename = ‘WARD‘ );
查询部门名为‘SALES‘的员工信息(方式一:子查询)
第一:查询部门名为‘SALES‘的编号? select deptno from dept where dname = ‘SALES‘; 第二:查询部门号为30的员工信息? select * from emp where deptno = 30; 子查询: select * from emp where deptno = ( select deptno from dept where dname = ‘SALES‘ );
子查询细节: 1)子查询与父查询可以针对同一张表 2)子查询与父查询可以针对不同张表 3) 子查询与父查询在传统参数时,数量要相同 4) 子查询与父查询在传统参数时,类型要相同 5) 子查询与父查询在传统参数时,含义要相同
查询部门名为‘SALES‘的员工信息(方式二:多表查询) select emp.* from dept,emp where (dept.deptno=emp.deptno) and (dept.dname=‘SALES‘);
查询每个员工编号,姓名,部门名,工资等级(三表查询,这三张表并无外健关联) select e.empno,e.ename,d.dname,s.grade from emp e,dept d,salgrade s where (e.deptno=d.deptno) and (e.sal between s.losal and s.hisal);
查询工资最低的员工信息(单行子查询,使用=号) 第一:查询出工资最低是多少? select min(sal) from emp; 第二:查询工资为800的员工信息? select * from emp where sal = 800; 子查询: select * from emp where sal = ( select min(sal) from emp );
查询部门名为‘ACCOUNTING‘或‘SALES‘的员工信息(多行子查询,使用in关键字) 第一:查询部门名为‘ACCOUNTING‘或‘SALES‘的部门编号? select deptno from dept where dname in (‘ACCOUNTING‘,‘SALES‘); 第二:查询部门号为10或30号的员工信息? select * from emp where deptno in (10,30); 子查询: select * from emp where deptno in ( select deptno from dept where dname in (‘ACCOUNTING‘,‘SALES‘) );
查询工资比20号部门【任意any】一个员工工资【低<】的员工信息(多行子查询,使用any关键字) 第一:查询20号部门的所有工资? select sal from emp where deptno = 20; 第二:查询工资比(800,2975,3000,1100,3000)任意一个低的员工信息? select * from emp where sal < any (800,2975,3000,1100,3000); 在oracle看来,<any就等于<集合中最大的那个值 子查询: select * from emp where sal <any ( select sal from emp where deptno = 20 );
查询工资比30号部门【所有all】员工【低<】的员工信息(多行子查询,使用all关键字)
第一:查询出30部门所有员工的工资? select sal from emp where deptno = 30; 第二:查询工资比(1600,1250,1250,2850,1500,950)中所有的工资都低的员工信息? select * from emp where sal <all (1600,1250,1250,2850,1500,950); 子查询: select * from emp where sal <all ( select sal from emp where deptno = 30 );
注意:学员们,不容易理解的几个概念:
单行函数:输入一个参数,输出一个结果 多行函数:扫描多个参数,输出一个结果
单行子查询:子查询只会返回一个结果,例如:800,父查询用=/<>/>=/<=这些符号来比较 多行子查询:子查询会返回多于一个结果,例如:30,20,父查询用in/any/all这些符号来比较
当多表查询,子查询同时能解决问题时,按如下优先方案选择:
多表查询-->子查询 注意:上述结果不是说多表查询可以替代子查询,某些情况下,只能用子查询解决,例如:oracle分页 |
2.12,集合查询
2.12.1,案例
使用并集运算,查询20号部门或30号部门的员工信息 select * from emp where deptno = 20 union select * from emp where deptno = 30; 注意: union:二个集合中,如果都有相同的,取其一 union all:二个集合中,如果都有相同的,都取
使用set time/timing on,打开时间的开关 set time on; set time off;
使用set tim/timing off,关闭时间的开关 set timing on; set timint off;
使用交集运算[intersect],查询工资在1000-2000和1500-2500之间的员工信息(方式一) select * from emp where sal between 1000 and 2000 intersect select * from emp where sal between 1500 and 2500;
用where行过滤,查询工资在1000-2000和1500-2500之间的员工信息(方式二) select * from emp where (sal between 1000 and 2000) and (sal between 1500 and 2500);
使用差集运算[minus],查询工资在1000-2000,但不在1500-2500之间的员工信息(方式一) select * from emp where sal between 1000 and 2000 minus select * from emp where sal between 1500 and 2500;
使用where行过滤,查询工资在1000-2000,但不在1500-2500之间的员工信息(方式二) select * from emp where (sal between 1000 and 2000) and (sal not between 1500 and 2500);
集合查询的细节: 1)集合操作时,必须确保集合列数是相等 select empno,ename,sal,comm from emp where deptno = 20 union select empno,ename,sal from emp where deptno = 30;错
2)集合操作时,必须确保集合列类型对应相同 select empno,ename,sal,comm from emp where deptno = 20 union select empno,ename,sal,hiredate from emp where deptno = 30;错
3)A union B union C = C union B union A select * from emp where deptno = 10 union select * from emp where deptno = 20 union select * from emp where deptno = 30;
4)当多个集合操作时,结果的列名由第一个集合列名决定 select empno "编号",ename "姓名",sal "薪水" from emp where deptno = 20 union select empno,ename,sal from emp where deptno = 10;
当多表查询,子查询,集合查询都能完成同样任务时,按如下优化方案选择: 多表查询->子查询->集合查询 |
2.13,分页
2.13.1,案例
回顾mysql分页 用limit关键字
查询users表中前二条记录 select * from users limit 0,2 或 select * from users limit 2; 0表示第一条记录的索引号,索引号从0开始 2表示最多选取二个记录
查询出users前三条记录 select * from users limit 0,3 或 select * from users limit 3
查询出users第2条到第4条记录 select * from users limit 1,3;
回顾hibernate分页API Query.setFirstResult(0); Query.setMaxResult(3);
什么是rownum,有何特点 1)rownum是oracle专用的关健字 2)rownum与表在一起,表亡它亡,表在它在 3)rownum在默认情况下,从表中是查不出来的 4)只有在select子句中,明确写出rownum才能显示出来 5)rownum是number类型,且唯一连续 6)rownum最小值是1,最大值与你的记录条数相同 7)rownum也能参与关系运算 * rownum = 1 有值 * rownum < 5 有值 * rownum <=5 有值 * rownum > 2 无值 * rownum >=2 无值 * rownum <>2 有值 与 rownum < 2 相同 * rownum = 2 无值 8)基于rownum的特性,我们通常rownum只用于<或<=关系运算
显示emp表中3-8条记录(方式一:使用集合减运算) select rownum "伪列",emp.* from emp where rownum<=8 minus select rownum,emp.* from emp where rownum<=2;
显示emp表中3-8条记录(方式二:使用子查询,在from子句中使用,重点) select xx.* from (select rownum ids,emp.* from emp where rownum<=8) xx where ids>=2; 注意:在子查询中的别名,不可加""引号
显示emp表中5-9条记录 select yy.* from (select rownum ids,emp.* from emp where rownum<=9) yy where ids>=5; 注意:在项目中,from后台可能有真实表名,也可能用子查询看作的表名, 同时真实表和子查询看作的表要做连接查询 |
2.14,创建表和约束
2.14.1,案例
回顾MySQL创建表语句users(id整型/name字符串/birthday日期型,默认今天) drop table if exists users; create table if not exists users( id int(5) auto_increment primary key, name varchar(4) not null, birthday date default ‘2015-4-27‘ );
使用oracleSQL,创建用户表users(id整型/name字符串/birthday日期/sal整型,默认今天) create table users( id number(5) primary key, name varchar2(8) not null unique, sal number(6,2) not null, birthday date default sysdate );
进入回收站 drop table users;
查询回收站中的对象 show recyclebin;
闪回,即将回收站还原 flashback table 表名 to before drop; flashback table 表名 to before drop rename to 新表名;
彻底删除users表 drop table users purge;
清空回收站 purge recyclebin;
测试如下类型 (1)number(5): insert into users(id,name,sal) values(1,‘A‘,6666.66); insert into users(id,name,sal) values(11,‘AA‘,6666.66); insert into users(id,name,sal) values(111,‘AAA‘,6666.66); insert into users(id,name,sal) values(1111,‘AAAA‘,6666.66); insert into users(id,name,sal) values(99999,‘AAAAA‘,6666.66); insert into users(id,name,sal) values(100000,‘AAAAAA‘,6666.66); 错 5表示最多存99999
(2)number(6,2): col sal for 9999.99 insert into users(id,name,sal) values(1,‘A‘,6.66); insert into users(id,name,sal) values(11,‘AA‘,66.666); insert into users(id,name,sal) values(111,‘AAA‘,666.6666); insert into users(id,name,sal) values(1111,‘AAAA‘,6666.66666); insert into users(id,name,sal) values(11111,‘AAAAA‘,66666.666666);错 number(6,2) 其中2表示最多显示2位小数,采用四舍五入,不足位数补0,同时要设置col ... for ... 其中6表示小数+整数不多于6位 其中整数位数不得多于4位,可以等于4位
(3)varchar2(8): insert into users(id,name,sal) values(1,‘A‘,7777.77); insert into users(id,name,sal) values(2,‘AA‘,7777.77); insert into users(id,name,sal) values(3,‘AAA‘,7777.77); insert into users(id,name,sal) values(4,‘AAAA‘,7777.77); insert into users(id,name,sal) values(5,‘AAAAA‘,7777.77); insert into users(id,name,sal) values(6,‘AAAAAA‘,7777.77); insert into users(id,name,sal) values(7,‘AAAAAAA‘,7777.77); insert into users(id,name,sal) values(8,‘AAAAAAAA‘,7777.77); insert into users(id,name,sal) values(9,‘AAAAAAAAA‘,7777.77);错
insert into users(id,name,sal) values(1,‘哈‘,7777.77); insert into users(id,name,sal) values(2,‘哈哈‘,7777.77); insert into users(id,name,sal) values(3,‘哈哈哈‘,7777.77); insert into users(id,name,sal) values(4,‘哈哈哈哈‘,7777.77); insert into users(id,name,sal) values(5,‘哈哈哈哈哈‘,7777.77);错
8表示字节 GBK 赵 2字节
(4)date:默认格式为:‘27-4月-15‘ (5)CLOB【Character Large OBject】:大文本对象,即超过65565字节的数据对象,最多存储4G (6)BLOB【Binary Large OBject】:大二进制对象,即图片,音频,视频,最多存储4G
为emp表增加image列,alter table 表名 add 列名 类型(宽度) alter table emp add image blob;
修改ename列的长度为20个字节,alter table 表名 modify 列名 类型(宽度) alter table emp modify ename varchar2(20);
删除image列,alter table 表名 drop column 列名 alter table emp drop column image;
重名列名ename为username,alter table 表名 rename column 原列名 to 新列名 alter table emp rename column ename to username;
将emp表重命名emps,rename 原表名 to 新表名 rename emp to emps;
注意:修改表时,不会影响表中原有的数据
笔试题:有【1000亿】条会员记录,如何用最高效的方式将薪水字段清零,其它字段内容不变?
第一:从emp表中删除sal字段 alter table emp drop column sal;
第二:向emp表中添加sal字段,且内容默认0 alter table emp add sal number(6) default 0;
修改表不可回滚
创建表customers(单)和orders(多),使用primary key/not null/unique/default/foreign key约束 要体现【on delete cascade/on delete set null】 需求:删除客户,级联删除他所有的订单 delete from customers where id = 1; 需求:删除客户,不级联删除他所有的订单,只是将外健设置为NULL delete from customers where id = 1;
create table customers( id number(3) primary key, name varchar2(4) not null unique ); insert into customers(id,name) values(1,‘A‘); insert into customers(id,name) values(2,‘B‘);
create table orders( id number(3) primary key, isbn varchar2(6) not null unique, price number(3) not null, cid number(3), --constraint cid_FK foreign key(cid) references customers(id) on delete cascade constraint cid_FK foreign key(cid) references customers(id) on delete set null ); insert into orders(id,isbn,price,cid) values(1,‘isbn10‘,10,1); insert into orders(id,isbn,price,cid) values(2,‘isbn20‘,20,1); insert into orders(id,isbn,price,cid) values(3,‘isbn30‘,30,2); insert into orders(id,isbn,price,cid) values(4,‘isbn40‘,40,2);
创建表students,包括id,name,gender,salary字段,使用check约束【性别只能是男或女,薪水介于6000到8000之间】 create table students( id number(3) primary key, name varchar2(4) not null unique, gender varchar2(2) not null check ( gender in (‘男‘,‘女‘) ), salary number(6) not null check ( salary between 6000 and 8000 ) ); insert into students(id,name,gender,salary) values(1,‘哈哈‘,‘中‘,6000);错 insert into students(id,name,gender,salary) values(2,‘呵呵‘,‘男‘,5000);错 insert into students(id,name,gender,salary) values(3,‘嘻嘻‘,‘女‘,7000);对
|
2.15,增删改数据
2.15.1,案例
回顾SQL92/99标准的四大类 (1)DML(数据操纵语言):select,insert,update,delete (2)DDL(数据定义语言):create table,alter table,drop table,truncate table (3)DCL(数据控制语言):grant select any table to scott/revoke select any table from scott (4)TCL(事务控制语言):commit,rollback,savepoint to 回滚点
向emp表中插入一条记录(方式一:按表默认结构顺序)insert into 表名 values ...语法 insert into emp values(1111,‘JACK‘,‘IT‘,7788,sysdate,1000,100,40);
向emp表中插入一条记录(方式二:按自定义顺序)insert into 表名(列名) values ...语法 insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values(‘MARRY‘,2222,‘IT‘,7788,sysdate,1000,100,40);
向emp表中插入NULL值(方式一:采用显示插入NULL值) insert into emp values(3333,‘SISI‘,‘IT‘,7788,sysdate,1000,NULL,40);
向emp表中插入NULL值 (方式二:采用隐式插入NULL值),前提是所插入的字段允许插入NULL值 insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,DEPTNO) values(‘SOSO‘,4444,‘IT‘,7788,sysdate,1000,40);
使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在values子句中使用,例如:‘&ename‘和&sal insert into emp values(&empno,‘&ename‘,‘&job‘,&mgr,&hiredate,&sal,&comm,&xxxxxxxx); 注意:&是sqlplus工具提供的占位符,如果是字符串或日期型要加‘‘符,数值型无需加‘‘符
使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在from子句中使用 select * from &table;
使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在select子句中使用 select empno,ename,&colname from emp;
使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在where子句中使用 select * from emp where sal > &money;
使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在group by 和 having子句中使用 select deptno,avg(sal) from emp group by &deptno having avg(sal) > &money;
删除emp表中的所有记录 delete from emp;
将xxx_emp表中所有20号部门的员工,复制到emp表中,批量插入,insert into 表名 select ...语法 insert into emp select * from xxx_emp where deptno=20;
将‘SMITH‘的工资增加20% update emp set sal=sal*1.2 where ename = upper(‘smith‘);
将‘SMITH‘的工资设置为20号部门的平均工资,这是一个条件未知的事物,优先考虑子查询 第一:20号部门的平均工资 select avg(sal) from emp where deptno=20; 第二:将‘SMITH‘的工资设置为2207 update emp set sal=2207 where ename = ‘SMITH‘; 子查询: update emp set sal = ( select avg(sal) from emp where deptno=20 ) where ename = ‘SMITH‘;
删除工资比所有部门平均工资都低的员工,这是一个条件未知的事物,优先考虑子查询 第一:查询所有部门的平均工资 select avg(sal) from emp group by deptno; 第二:删除工资比(*,*,*)都低的员工 delete from emp where sal<all(*,*,*); 子查询: delete from emp where sal < all( select avg(sal) from emp group by deptno );
删除无佣金的员工 delete from emp where comm is null;
将emp表丢入回收站,drop table 表名 drop table emp;
从回收站将emp表闪回,flashback table 表名 to before drop flashback table emp to before drop;
查询回收站,show recyclebin show recyclebin;
清空回收站,purge recyclebin purge recyclebin;
使用关键字purge,彻底删除emp表,即不会将emp表丢入回收站,永久删除emp表,drop table 表名 purge drop table emp purge;
依据xxx_emp表结构,创建emp表的结构,但不会插入数据 create table emp as select * from xxx_emp where 1<>1;
创建emp表,复制xxx_emp表中的结构,同时复制xxx_emp表的所有数据 create table emp as select * from xxx_emp where 1=1; 注意:where不写的话,默认为true
将emp截断,再自动创建emp表,truncate table 表名 truncate table emp;
向emp表,批量插入来自xxx_emp表中部门号为20的员工信息,只包括empno,ename,job,sal字段 insert into emp(empno,ename,job,sal) select empno,ename,job,sal from xxx_emp where deptno=20;
使用关键字purge,彻底删除emp表,即不会将emp表丢入回收站 drop table emp purge;
依据xxx_emp表,只创建emp表,但不复制数据,且emp表只包括empno,ename字段 create table emp(empno,ename) as select empno,ename from xxx_emp where 1=2;
向emp表(只含有empno和ename字段),批量插入xxx_emp表中部门号为20的员工信息 insert into emp(empno,ename) select empno,ename from xxx_emp where deptno=20;
drop table 和 truncate table 和 delete from 区别: drop table 1)属于DDL 2)不可回滚 3)不可带where 4)表内容和结构删除 5)删除速度快
truncate table 1)属于DDL 2)不可回滚 3)不可带where 4)表内容删除 5)删除速度快
delete from 1)属于DML 2)可回滚 3)可带where 4)表结构在,表内容要看where执行的情况 5)删除速度慢,需要逐行删除 软件工程师 |
2.16,事务
2.16.1,案例
回顾什么是事务? 一个不可分割的子操作形成一个整体,该整体要么全部执行成功,要么全部执行失败。例如:转帐
回顾为什么要用事务? 如果不用事务的话,为转帐为例,可能出现一个用户钱增加了,另一个用户钱不变
回顾编程中,事务可用于哪一层? 事务放在业务层
回顾jdbc编程中,如何使用事务? connection.setAutoCommit(false); pstmt.executeUpdate(); connection.commit(); connection.rollback();
回顾hibernate编程中,如何使用事务? transaction.begin(); session.save(new User()); transaction.commit(); transaction.rollback();
回顾spring编程中,如何使用事务? spring可以分为二种 >编程式事务,藕合 >声明式事务,解藕,提倡
Oracle的事务只针对DML操作,即select/insert/update/delete
回顾MySQL的事务开始:start transaction Oracle的事务开始:第一条DML操作做为事务开始
Oracle的提交事务 (1)显示提交:commit (2)隐藏提交:DDL/DCL/exit(sqlplus工具) 注意:提交是的从事务开始到事务提交中间的内容,提交到ORCL数据库中的DBF二进制文件
Oracle的回滚事务 (1)显示回滚:rollback (2)隐藏回滚:关闭窗口(sqlplus工具),死机,掉电 注意:回滚到事务开始的地方
回顾什么是回滚点? 在操作之间设置的一个标志位,用于将来回滚之用
回顾为什么要设置回滚点?savepoint a;rollback to savepoint a; 如果没有设置回滚点的话,Oracle必须回滚到事务开始的地方,其间做的一个正确的操作也将撤销
使用savepoint 回滚点,设置回滚点a savepoint a;
使用rollback to savepoint,回滚到回滚点a处 rollback to savepoint a;
Oracle提交或回滚后,原来设置的回滚点还有效吗? 原回滚点无效了
Oracle之所以能回滚的原因是? 主要机制是实例池
回顾MySQL支持的四种事务隔离级别及能够解决的问题 (1)read uncommitted -- 不能解决任何缺点 (2)read committed -- 脏读,Oracle默认 (3)reapatable read -- 不可重复读,脏读,MySQL默认 (4)serializable -- 幻读,不可重复读,脏读,效率低
注意:jdbc/dbutils速度快,但书写烦 mybaits速度中等,但书写"中等" hibernate速度慢,但书写"爽"
Oracle支持的二种事务隔离级别及能够解决的问题 Oracle支持:read committed 和 serializable
Oracle中设置事务隔离级别为serializable set transaction isolation level serializable;
演示二个用户同时操作emp表,删除KING这条记录,会有什么后果? 因为有隔离级别的存在,所以不会出现二个用户都删除了KING这条记录, 一定是一个用户删除KING成功,在该用户没有提交的情况下,另一个用户等待 |
2.17,访问其它用户下的对象
2.17.1,案例
声明:scott或hr叫用户名/方案名/空间名 scott--tiger hr-----lion
查询当前用户是谁 show user;
查询scott自己表空间下的所有对象时,可加,或不加用户名select * from emp; select * from emp; 或 select * from scott.emp;
以sysdba身份解锁hr普通帐户 alter user hr account unlock;
以sysdba身份设置hr普通帐户的密码 alter user hr identified by lion;
当scott查询hr表空间下的所有表时,必须得加用户名 select * from hr.jobs;
在默认情况下,每个用户只能查询自已空间下的对象的权限,不能查询其它用户空间下的对象
以sysdba身份角色,授予scott用户查询所有用户空间下的对象权限 grant select any table to scott;
以sysdba身份,撤销scott用户查询所有用户空间下的对象权限 revoke select any table from scott;
scott自已查看自己所拥有的权限 select * from user_sys_privs;
从scott用户空间导航到sysdba用户空间 conn / as sysdba;
从sysdba用户空间导航到scott用户空间 conn scott/tiger;
从scott用户空间导航到hr用户空间 conn hr/lion;
查询hr用户空间中的所有对象 select * from tab;
从hr用户空间导航到scott用户空间 conn scott/tiger;
在scott用户空间下,查询hr用户空间下的jobs表,必须加上hr用户空间名 select * from hr.jobs; |
2.18,视图
2.18.1,案例
什么是视图【View】 (1)视图是一种虚表 (2)视图建立在已有表的基础上, 视图赖以建立的这些表称为基表 (3)向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELECT 语句 (4)视图向用户提供基表数据的另一种表现形式 (5)视图没有存储真正的数据,真正的数据还是存储在基表中 (6)程序员虽然操作的是视图,但最终视图还会转成操作基表 (7)一个基表可以有0个或多个视图
什么情况下会用到视图 (1)如果你不想让用户看到所有数据(字段,记录),只想让用户看到某些的数据时,此时可以使用视图 (2)当你需要减化SQL查询语句的编写时,可以使用视图,但不提高查询效率
视图应用领域 (1)银行,电信,金属,证券军事等不便让用户知道所有数据的项目中
视图的作用 (1)限制数据访问 (2)简化复杂查询 (3)提供数据的相互独立 (4)同样的数据,可以有不同的显示方式
基于emp表所有列,创建视图emp_view_1,create view 视图名 as select对一张或多张基表的查询 create view emp_view_1 as select * from emp;
默认情况下,普通用户无权创建视图,得让sysdba为你分配creare view的权限
以sysdba身份,授权scott用户create view权限 grant create view to scott;
以sysdba身份,撤销scott用户create view权限 revoke create view from scott;
基于emp表指定列,创建视图emp_view_2,该视图包含编号/姓名/工资/年薪/年收入(查询中使用列别名) create view emp_view_2 as select empno "编号",ename "姓名",sal "工资",sal*12 "年薪",sal*12+NVL(comm,0) "年收入" from emp;
基于emp表指定列,创建视图emp_view_3(a,b,c,d,e),包含编号/姓名/工资/年薪/年收入(视图中使用列名) create view emp_view_3(a,b,c,d,e) as select empno "编号",ename "姓名",sal "工资",sal*12 "年薪",sal*12+NVL(comm,0) "年收入" from emp;
查询emp_view_3创建视图的结构 desc emp_view_3;
修改emp_view_3(id,name,salary,annual,income)视图,create or replace view 视图名 as 子查询 create or replace view emp_view_3(id,name,salary,annual,income) as select empno "编号",ename "姓名",sal "工资",sal*12 "年薪",sal*12+NVL(comm,0) "年收入" from emp;
查询emp表,求出各部门的最低工资,最高工资,平均工资 select min(sal),max(sal),round(avg(sal),0),deptno from emp group by deptno;
创建视图emp_view_4,视图中包含各部门的最低工资,最高工资,平均工资 create or replace view emp_view_4 as select deptno "部门号",min(sal) "最低工资",max(sal) "最高工资",round(avg(sal),0) "平均工资" from emp group by deptno;
创建视图emp_view_5,视图中包含员工编号,姓名,工资,部门名,工资等级 create or replace view emp_view_5 as select e.empno "编号",e.ename "姓名",e.sal "工资",d.dname "部门名",s.grade "工资等级" from emp e,dept d,salgrade s where (e.deptno=d.deptno) and (e.sal between s.losal and s.hisal);
删除视图emp_view_1中的7788号员工的记录,使用delete操作,会影响基表吗 delete from emp_view_1 where empno=7788;写法正确,会影响基表
修改emp_view_1为只读视图【with read only】,再执行上述delete操作,还行吗? create or replace view emp_view_1 as select * from emp with read only; 不能进行delete操作了
删除视图中的【某条】记录会影响基表吗? 会影响基表
将【整个】视图删除,会影响表吗? 不会影响基表
删除视图,会进入回收站吗? 不会进入回收站
删除基表会影响视图吗? 会影响视图
闪回基表后,视图有影响吗? 视图又可以正常工作了 |
2.19,同义词
2.19.1,案例
什么是同义词【Synonym】 (1)对一些比较长名字的对象(表,视图,索引,序列,。。。)做减化,用别名替代
同义词的作用 (1)缩短对象名字的长度 (2)方便访问其它用户的对象
创建与salgrade表对应的同义词,create synonym 同义词 for 表名/视图/其它对象 create synonym e for salgrade; create synonym ev5 for emp_view_5;
以sys身份授予scott普通用户create synonym权限 grant create synonym to scott;
以sys身份从scott普通用户撤销create synonym权限 revoke create synonym from scott;
使用同义词操作salgrade表 select * from s;
删除同义词 drop synonym ev5;
删除同义词,会影响基表吗? 不会影响基表
删除基表,会影响同义词吗? 会影响同义词 |
2.20,序列
2.20.1,案例
什么是索引【Index】 (1)是一种快速查询表中内容的机制,类似于新华字典的目录 (2)运用在表中某个/些字段上,但存储时,独立于表之外
为什么要用索引 (1)通过指针加速Oracle服务器的查询速度 (2)通过rowid快速定位数据的方法,减少磁盘I/O rowid是oracle中唯一确定每张表不同记录的唯一身份证
rowid的特点 (1)位于每个表中,但表面上看不见,例如:desc emp是看不见的 (2)只有在select中,显示写出rowid,方可看见 (3)它与每个表绑定在一起,表亡,该表的rowid亡,二张表rownum可以相同,但rowid必须是唯一的 (4)rowid是18位大小写加数字混杂体,唯一表代该条记录在DBF文件中的位置 (5)rowid可以参与=/like比较时,用‘‘单引号将rowid的值包起来,且区分大小写 (6)rowid是联系表与DBF文件的桥梁
索引的特点 (1)索引一旦建立, Oracle管理系统会对其进行自动维护, 而且由Oracle管理系统决定何时使用索引 (2)用户不用在查询语句中指定使用哪个索引 (3)在定义primary key或unique约束后系统自动在相应的列上创建索引 (4)用户也能按自己的需求,对指定单个字段或多个字段,添加索引
什么时候【要】创建索引 (1)表经常进行 SELECT 操作 (2)表很大(记录超多),记录内容分布范围很广 (3)列名经常在 WHERE 子句或连接条件中出现 注意:符合上述某一条要求,都可创建索引,创建索引是一个优化问题,同样也是一个策略问题
什么时候【不要】创建索引 (1)表经常进行 INSERT/UPDATE/DELETE 操作 (2)表很小(记录超少) (3)列名不经常作为连接条件或出现在 WHERE 子句中 同上注意
为emp表的empno单个字段,创建索引emp_empno_idx,叫单列索引,create index 索引名 on 表名(字段,...) create index emp_empno_idx on emp(empno);
为emp表的ename,job多个字段,创建索引emp_ename_job_idx,多列索引/联合索引 create index emp_ename_job on emp(ename,job); 如果在where中只出现job不使用索引 如果在where中只出现ename使用索引 我们提倡同时出现ename和job
注意:索引创建后,只有查询表有关,和其它(insert/update/delete)无关,解决速度问题
删除emp_empno_idx和emp_ename_job_idx索引,drop index 索引名 drop index emp_empno_idx; drop index emp_ename_job_idx; |
2.21,SQL对比PLSQL
2.21.1,案例
SQL99是什么 (1)是操作所有关系型数据库的规则 (2)是第四代语言 (3)是一种结构化查询语言 (4)只需发出合法合理的命令,就有对应的结果显示
SQL的特点 (1)交互性强,非过程化 (2)数据库操纵能力强,只需发送命令,无需关注如何实现 (3)多表操作时,自动导航简单,例如: select emp.empno,emp.sal,dept.dname from emp,dept where emp.deptno = dept.deptno (4)容易调试,错误提示,直接了当 (5)SQL强调结果
PLSQL是什么 是专用于Oracle服务器,在SQL基础之上,添加了一些过程化控制语句,叫PLSQL 过程化包括有:类型定义,判断,循环,游标,异常或例外处理。。。 PLSQL强调过程
为什么要用PLSQL 因为SQL是第四代命令式语言,无法显示处理过程化的业务,所以得用一个过程化程序设计语言来弥补SQL的不足之处, SQL和PLSQL不是替代关系,是弥补关系
PLSQL程序的完整组成结构如下: [declare] 变量声明; 变量声明; begin DML/TCL操作; DML/TCL操作; [exception] 例外处理; 例外处理; end; / 注意:在PLSQL程序中,;号表示每条语句的结束,/表示整个PLSQL程序结束
书写PLSQL的工具有: (1)SQLPLUS工具 (2)SQLDeveloper工具 (3)第三方工具(PLSQL & 其它)
PLSQL与SQL执行有什么不同: (1)SQL是单条执行的 (2)PLSQL是整体执行的,不能单条执行,整个PLSQL结束用/,其中每条语句结束用 |
2.22,PLSQL类型
2.22.1,案例
写一个PLSQL程序,输出"hello world"字符串,语法:dbms_output.put_line(‘需要输出的字符串‘); begin --向SQLPLUS客户端工具输出字符串 dbms_output.put_line(‘hello 你好‘); end; /
注意: dbms_output是oracle中的一个输出对象 put_line是上述对象的一个方法,用于输出一个字符串自动换行
设置显示PLSQL程序的执行结果,默认情况下,不显示PLSQL程序的执行结果,语法:set serveroutput on/off; set serveroutput on;
使用基本类型变量,常量和注释,求10+100的和 declare --定义变量 mysum number(3) := 0; tip varchar2(10) := ‘结果是‘; begin /*业务算法*/ mysum := 10 + 100; /*输出到控制器*/ dbms_output.put_line(tip || mysum); end; /
输出7369号员工姓名和工资,格式如下:7369号员工的姓名是SMITH,薪水是800,语法:使用表名.字段%type declare --定义二个变量,分别装姓名和工资 pename emp.ename%type; psal emp.sal%type; begin --SQL语句 --select ename,sal from emp where empno = 7369; --PLSQL语句,将ename的值放入pename变量中,sal的值放入psal变量中 select ename,sal into pename,psal from emp where empno = 7369; --输出 dbms_output.put_line(‘7369号员工的姓名是‘||pename||‘,薪水是‘||psal); end; /
输出7788号员工姓名和工资,格式如下:7788号员工的姓名是SMITH,薪水是3000,语法:使用表名%rowtype declare emp_record emp%rowtype; begin select * into emp_record from emp where empno = 7788; dbms_output.put_line(‘7788号员工的姓名是‘||emp_record.ename||‘,薪水是‘||emp_record.sal); end; /
何时使用%type,何时使用%rowtype? 当定义变量时,该变量的类型与表中某字段的类型相同时,可以使用%type 当定义变量时,该变量与整个表结构完全相同时,可以使用%rowtype,此时通过变量名.字段名,可以取值变量中对应的值 项目中,常用%type |
2.23,PLSQL判断
2.23.1,案例
使用if-else-end if显示今天星期几,是"工作日"还是"休息日" declare pday varchar2(10); begin select to_char(sysdate,‘day‘) into pday from dual; dbms_output.put_line(‘今天是‘||pday); if pday in (‘星期六‘,‘星期日‘) then dbms_output.put_line(‘休息日‘); else dbms_output.put_line(‘工作日‘); end if; end; /
从键盘接收值,使用if-elsif-else-end if显示"age<16","age<30","age<60","age<80" declare age number(3) := &age; begin if age < 16 then dbms_output.put_line(‘你未成人‘); elsif age < 30 then dbms_output.put_line(‘你青年人‘); elsif age < 60 then dbms_output.put_line(‘你奋斗人‘); elsif age < 80 then dbms_output.put_line(‘你享受人‘); else dbms_output.put_line(‘未完再继‘); end if; end; / |
2.24,-PLSQL循环
2.24,案例
使用loop循环显示1-10 declare i number(2) := 1; begin loop --当i>10时,退出循环 exit when i>10; --输出i的值 dbms_output.put_line(i); --变量自加 i := i + 1; end loop; end; /
使用while循环显示1-10 declare i number(2) := 1; begin while i<11 loop dbms_output.put_line(i); i := i + 1; end loop; end; /
使用while循环,向emp表中插入999条记录 declare i number(4) := 1; begin while( i < 1000 ) loop insert into emp(empno,ename) values(i,‘哈哈‘); i := i + 1; end loop; end; /
使用while循环,从emp表中删除999条记录 declare i number(4) := 1; begin while i<1000 loop delete from emp where empno = i; i := i + 1; end loop; end; /
使用for循环显示20-30 declare i number(2) := 20; begin for i in 20 .. 30 loop dbms_output.put_line(i); end loop; end; / |
2.25,PLSQL游标
2.25.1,案例
什么是光标/游标/cursor 类似于JDBC中的ResultSet对象的功能,从上向下依次获取每一记录的内容
使用无参光标cursor,查询所有员工的姓名和工资【如果需要遍历多条记录时,使用光标cursor,无记录找到使用cemp%notfound】 declare --定义游标 cursor cemp is select ename,sal from emp; --定义变量 vename emp.ename%type; vsal emp.sal%type; begin --打开游标,这时游标位于第一条记录之前 open cemp; --循环 loop --向下移动游标一次 fetch cemp into vename,vsal; --退出循环,当游标下移一次后,找不到记录时,则退出循环 exit when cemp%notfound; --输出结果 dbms_output.put_line(vename||‘--------‘||vsal); end loop; --关闭游标 close cemp; end; /
使用带参光标cursor,查询10号部门的员工姓名和工资 declare cursor cemp(pdeptno emp.deptno%type) is select ename,sal from emp where deptno=pdeptno; pename emp.ename%type; psal emp.sal%type; begin open cemp(&deptno); loop fetch cemp into pename,psal; exit when cemp%notfound; dbms_output.put_line(pename||‘的薪水是‘||psal); end loop; close cemp; end; /
使用无参光标cursor,真正给员工涨工资,ANALYST涨1000,MANAGER涨800,其它涨400,要求显示编号,姓名,职位,薪水 declare cursor cemp is select empno,ename,job,sal from emp; pempno emp.empno%type; pename emp.ename%type; pjob emp.job%type; psal emp.sal%type; begin open cemp; loop fetch cemp into pempno,pename,pjob,psal; --循环退出条件一定要写 exit when cemp%notfound; if pjob=‘ANALYST‘ then update emp set sal = sal + 1000 where empno = pempno; elsif pjob=‘MANAGER‘ then update emp set sal = sal + 800 where empno = pempno; else update emp set sal = sal + 400 where empno = pempno; end if; end loop; commit; close cemp; end; / |
2.26,PLSQL例外
2.26.1,案例
使用oracle系统内置例外,演示除0例外【zero_divide】 declare myresult number; begin myresult := 1/0; dbms_output.put_line(myresult); exception when zero_divide then dbms_output.put_line(‘除数不能为0‘); delete from emp; end; /
使用oracle系统内置例外,查询100号部门的员工姓名,演示没有找到数据【no_data_found】 declare pename varchar2(20); begin select ename into pename from emp where deptno = 100; dbms_output.put_line(pename); exception when NO_DATA_FOUND then dbms_output.put_line(‘查无该部门员工‘); insert into emp(empno,ename) values(1111,‘ERROR‘); end; /
使用用户自定义例外,使用光标cursor,查询10/20/30/100号部门的员工姓名,演示没有找到数据【nohave_emp_found】 |
2.27,存储过程概念
2.27.1,案例
什么是存储过程【procedure】?
为什么要用存储过程? (1)PLSQL每次执行都要整体运行一遍,才有结果 (2)PLSQL不能将其封装起来,长期保存在oracle服务器中 (3)PLSQL不能被其它应用程序调用,例如:Java
存储过程与PLSQL是什么关系?
--------------------------------------------------------存储过程
创建无参存储过程hello,无返回值,语法:create or replace procedure 过程名 as PLSQL程序
删除存储过程hello,语法:drop procedure 过程名
调用存储过程方式一,exec 存储过程名
调用存储过程方式二,PLSQL程序
调用存储过程方式三,Java程序
创建有参存储过程raiseSalary(编号),为7369号员工涨10%的工资,演示in的用法,默认in,大小写不敏感
创建有参存储过程findEmpNameAndSalAndJob(编号),查询7788号员工的的姓名,职位,月薪,返回多个值,演示out的用法
什么情况下用exec调用,什么情况下用PLSQL调用存储过程?
用存储过程,写一个计算个人所得税的功能 |
2.28,存储函数
2.28.1,案例
创建无参存储函数getName,有返回值,语法:create or replace function 函数名 return 返回类型 as PLSQL程序段
删除存储函数getName,语法:drop function 函数名
调用存储函数方式一,PLSQL程序
调用存储函数方式二,Java程序
创建有参存储函数findEmpIncome(编号),查询7369号员工的年收入,演示in的用法,默认in
创建有参存储函数findEmpNameAndJobAndSal(编号),查询7788号员工的的姓名(return),职位(out),月薪(out),返回多个值 |
2.29,过程函数适合场景
2.29.1,案例
声明:适合不是强行要你使用,只是优先考虑
什么情况下【适合使用】存储过程?什么情况下【适合使用】存储函数?
【适合使用】存储过程:
【适合使用】存储函数:
什么情况【适合使用】过程函数,什么情况【适合使用】SQL?
【适合使用】过程函数: 》需要长期保存在数据库中 》需要被多个用户重复调用 》业务逻辑相同,只是参数不一样 》批操作大量数据,例如:批量插入很多数据
【适合使用】SQL: 》凡是上述反面,都可使用SQL 》对表,视图,序列,索引,等这些还是要用SQL oracle中函数和存储过程的区别和联系 在oracle中,函数和存储过程是经常使用到的,他们的语法中有很多相似的地方,但也有自己的特点。刚学完函数和存储过程,下面来和大家分享一下自己总结的关于函数和存储过程的区别。 一、存储过程 1.定义 存储过程是存储在数据库中提供所有用户程序调用的子程序,定义存储过程的关键字为procedure。 2.创建存储过程 create [or replace] procedure 存储过程名 [(参数1 类型,参数2 out 类型……)] as 变量名 类型; begin 程序代码体 end; 示例一:无参无返
示例二:有参有返
示例三:参数列表中有in out参数
示例四:存储过程中定义参数
总结:1.创建存储过程的关键字为procedure。 2.传参列表中的参数可以用in,out,in out修饰,参数类型一定不能写大小。列表中可以有多个输入输出参数。 3.存储过程中定义的参数列表不需要用declare声明,声明参数类型时需要写大小的一定要带上大小。 4.as可以用is替换。 5.调用带输出参数的过程必须要声明变量来接收输出参数值。 6.执行存储过程有两种方式,一种是使用execute,另一种是用begin和end包住。 存储过程虽然有很多优点,但是它却不能使用return返回值。当需要使用return返回值时,我们可以使用函数。
二、存储函数 1.函数与存储过程的结构类似,但是函数必须有一个return子句,用于返回函数值。
三、存储过程与存储函数的区别和联系 相同点:1.创建语法结构相似,都可以携带多个传入参数和传出参数。 2.都是一次编译,多次执行。 不同点:1.存储过程定义关键字用procedure,函数定义用function。 2.存储过程中不能用return返回值,但函数中可以,而且函数中必须有return子句。 3.执行方式略有不同,存储过程的执行方式有两种(1.使用execute2.使用begin和end),函数除了存储过程的两种方式外,还可以当做表达式使用,例如放在select中(select f1() form dual;)。 总结:如果只有一个返回值,用存储函数,否则,一般用存储过程。 |
2.30,触发器
2.30.1,案例
什么是触发器【Trigger】?
为什么要用触发器?
创建语句级触发器insertEmpTrigger,当对表【emp】进行增加【insert】操作前【before】,显示"hello world"
删除触发器insertEmpTrigger,语法:drop trigger 触发器名
使用insert语句插入一条记录,引起insertEmpTrigger触发器工作
使用insert语句插入N条记录,引起insertEmpTrigger触发器工作
创建语句级触发器deleteEmpTrigger,当对表【emp】进行删除【delete】操作后【after】,显示"world hello"
使用delete语句删除一条记录,引起deleteEmpTrigger触发器工作
使用delete语句删除N条记录,引起deleteEmpTrigger触发器工作
星期一到星期五,且9-20点能向数据库emp表插入数据,否则使用函数抛出异常, 语法:raise_application_error(‘-20000‘,‘例外原因‘)
创建行级触发器checkSalaryTrigger,涨后工资这一列,确保大于涨前工资,语法:for each row/:new.sal/:old.sal
删除触发器,表还在吗?
将表丢到回收站,触发器还在吗?
当闪回表后,触发器会在吗?
彻底删除表,触发器会在吗? |
2.31,oracleSQL优化方案
2.31.1,案例
为什么要Oracle优化: 随着实际项目的启动,Oracle经过一段时间的运行,最初的Oracle设置,会与实际Oracle运行性能会有一些差异,这时我们 就需要做一个优化调整。
Oracle优化这个课题较大,可分为四大类: 》主机性能 》内存使用性能 》网络传输性能 》SQL语句执行性能【程序员】
下面列出一些oracleSQL优化方案:
(01)选择最有效率的表名顺序(笔试常考) ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名, FROM子句中写在最后的表将被最先处理, 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后, 如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。 例如:查询员工的编号,姓名,工资,工资等级,部门名 select emp.empno,emp.ename,emp.sal,salgrade.grade,dept.dname from salgrade,dept,emp where (emp.deptno = dept.deptno) and (emp.sal between salgrade.losal and salgrade.hisal) 1)如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推 2)如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推
(02)WHERE子句中的连接顺序(笔试常考) ORACLE采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。 例如:查询员工的编号,姓名,工资,部门名 select emp.empno,emp.ename,emp.sal,dept.dname from emp,dept where (emp.deptno = dept.deptno) and (emp.sal > 1500)
(03)SELECT子句中避免使用*号 ORACLE在解析的过程中,会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间 select empno,ename from emp;
(04)使用DECODE函数来减少处理时间 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表
(05)整合简单,无关联的数据库访问
(06)用TRUNCATE替代DELETE
(07)尽量多使用COMMIT 因为COMMIT会释放回滚点
(08)用WHERE子句替换HAVING子句 WHERE先执行,HAVING后执行
(09)多使用内部函数提高SQL效率
(10)使用表的别名 salgrade s
(11)使用列的别名 ename e
(12)用索引提高效率 在查询中,善用索引
(13)字符串型,能用=号,不用like 因为=号表示精确比较,like表示模糊比较
(14)SQL语句用大写的 因为Oracle服务器总是先将小写字母转成大写后,才执行 在eclipse中,先写小写字母,再通过ctrl+shift+X转大写;ctrl+shift+Y转小写
(15)避免在索引列上使用NOT 因为Oracle服务器遇到NOT后,他就会停止目前的工作,转而执行全表扫描
(16)避免在索引列上使用计算 WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描,这样会变得变慢 例如,SAL列上有索引, 低效: SELECT EMPNO,ENAME FROM EMP WHERE SAL*12 > 24000; 高效: SELECT EMPNO,ENAME FROM EMP WHERE SAL > 24000/12;
(17)用 >= 替代 > 低效: SELECT * FROM EMP WHERE DEPTNO > 3 首先定位到DEPTNO=3的记录并且扫描到第一个DEPT大于3的记录 高效: SELECT * FROM EMP WHERE DEPTNO >= 4 直接跳到第一个DEPT等于4的记录
(18)用IN替代OR select * from emp where sal = 1500 or sal = 3000 or sal = 800; select * from emp where sal in (1500,3000,800);
(19)总是使用索引的第一个列 如果索引是建立在多个列上,只有在它的第一个列被WHERE子句引用时,优化器才会选择使用该索引 当只引用索引的第二个列时,不引用索引的第一个列时,优化器使用了全表扫描而忽略了索引 create index emp_sal_job_idex on emp(sal,job); ---------------------------------- select * from emp where job != ‘SALES‘;
(20)避免改变索引列的类型,显示比隐式更安全 当字符和数值比较时,ORACLE会优先转换数值类型到字符类型 select 123 || ‘123‘ from dual;
总之,Oracle优化不是一天的课题,你得在长期工作实践中,进行反复测试与总结,希望学员们日后好好领会 |
以上是关于记忆------数据库代码块的主要内容,如果未能解决你的问题,请参考以下文章
一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式
<code> vs <pre> vs <samp> 用于内联和块代码片段
Android 逆向使用 DB Browser 查看并修改 SQLite 数据库 ( 从 Android 应用数据目录中拷贝数据库文件 | 使用 DB Browser 工具查看数据块文件 )(代码片段