最新Oracle基础教程(二)
文章目录
1 Oracle
1.1 序列
在很多数据库中都存在一个自动增长的列,如果现在要想在oracle 中完成自动增长的功能, 则只能依靠序列完成,所有的自动增长操作,需要用户手工完成处理。
语法:CREATE SEQUENCE 序列名
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE/ MINVALUE n|NOMAXVALUE}]
[{CYCLE|NOCYCLE}]
[{CACHE n|NOCACHE}];
范例:创建一个seqpersonid的序列,验证自动增长的操作CREATE SEQUENCE seqpersonid;
序列创建完成之后,所有的自动增长应该由用户自己处理,所以在序列中提供了以下的两种操作:
nextval :取得序列的下一个内容
currval :取得序列的当前内容
select seqpersonid.nextval from dual;
select seqpersonid.currval from dual;
在插入数据时需要自增的主键中可以这样使用
insert into person values(seqpersonid.nextval,'李四',1,null,'上海');
在实际项目中每一张表会配一个序列,但是表和序列是没有必然的联系的,一个序列被哪一张表使用都可以,但是我们一般都是一张表用一个序列。
序列的管理一般使用工具来管理。
1.2 约束
在数据库开发中,约束是必不可少,使用约束可以更好的保证数据的完整性。
1.2.1 主键约束
主键约束都是在id上使用,而且本身已经默认了内容不能为空,可以在建表的时候指定。
创建一张表,把pid作为主键
create table person(
pid number(10) primary key,
name varchar2(10),
gender number(1) default 1,
birthday date
);
我们可以自己来指定主键约束的名字
create table person(
pid number(10),
name varchar2(10),
gender number(1) default 1,
birthday date,
constraint person_pk_pid primary key(pid)
);
1.2.2 非空约束
使用非空约束,可以使指定的字段不可以为空。
范例:建立一张pid和name不可以为空的表
create table person(
pid number(10) not null,
name varchar2(10) not null,
gender number(1) ,
birthday date,
);
1.2.3 唯一约束
表中的一个字段的内容是唯一的
范例:建表一个name是唯一的表
create table person(
pid number(10) ,
name varchar2(10) unique,
gender number(1) ,
birthday date
);
唯一约束的名字也可以自定义
create table person(
pid number(10) ,
name varchar2(10),
gender number(1) ,
birthday date,
constraint person_name_uk unique(name)
);
1.2.4 检查约束
使用检查约束可以来约束字段值的合法范围。
范例:创建一张表性别只能是1或2
create table person(
pid number(10) ,
name varchar2(10),
gender number(1) check(gender in (1, 2)),
birthday date
);
检查约束也可以自定义
create table person(
pid number(10) ,
name varchar2(10),
gender number(1),
birthday date,
constraint person_gender_ck check(gender in (1,2))
);
1.2.5 外键约束
之前所讲的都是单表的约束,外键是两张表的约束,可以保证关联数据的完整性。
范例:创建两张表,一张订单表,一张是订单明细表,订单和明细是一对多的关系
create table orders(
order_id number(10) ,
total_price number(10,2),
order_time date,
constraint orders_order_id_pk primary key(order_id)
);
create table order_detail(
detail_id number(10) ,
order_id number(10),
item_name varchar2(10),
quantity number(10),
constraint order_detail_detail_id_pk primary key(detail_id)
);
insert into orders values(1, 200, to_date('2015-12-12','yyyy-MM-dd'));
insert into order_detail values(1, 2, 'java',1);
我们在两张表中插入如上两条数据,我们发现在order_detail表中插入的order_id在order表中并不存在,这样在数据库中就产生了脏数据。此时需要外键来约束它。
我们再次建表
create table orders(
order_id number(10) ,
total_price number(10,2),
order_time date,
constraint orders_order_id_pk primary key(order_id)
);
create table order_detail(
detail_id number(10) ,
order_id number(10),
item_name varchar2(10),
quantity number(10),
constraint order_detail_detail_id_pk primary key(detail_id),
constraint order_detail_order_id_fk foreign key(order_id) references orders(order_id)
);
外键关联一定注意:
- 外键一定是主表的主键
- 删表时一定先删子表再删主表,如果直接删主表会出现由于约束存在无法删除的问题
- 可以强制删除
drop table orders cascade constraint;
(不建议) - 删除主表的数据可以先删除子表的关联数据,再删主表,也可以使用级联删除。
- 级联删除在外键约束上要加上on delete cascade 如
constraint order_detail_order_id_fk foreign key(order_id) references orders(order_id) on delete cascade
这样删除主表数据的时候会把字表的关联数据一同删除
1.3 SQL
1.3.1 sql简介
结构化查询语言(Structured Query Language)简称SQL(发音:/ˈɛs kjuː ˈɛl/ “S-Q-L”),结构化查询语言是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;同时也是数据库脚本文件的扩展名。结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统, 可以使用相同的结构化查询语言作为数据输入与管理的接口。结构化查询语言语句可以嵌套,这使它具有极大的灵活性和强大的功能。
- DML(数据库操作语言): 其语句包括动词INSERT],UPDATE和DELETE。它们分别用于添加,修改和删除表中的行。也称为动作查询语言。
- DDL(数据库定义语言): 其语句包括动词CREATE和DROP。在数据库中创建新表或删除表(CREAT TABLE 或 DROP TABLE);为表加入索引等。DDL包括许多与人数据库目录中获得数据有关的保留字。它也是动作查询的一部分。
- DCL(数据库控制语言):它的语句通过GRANT或REVOKE获得许可,确定单个用户和用户 组对数据库对象的访问。某些RDBMS可用GRANT或REVOKE控制对表单个列的访问。
1.3.2 简单查询
使用scott下的表
oracle的scott用户下默认表
EMP(雇员表)
NO 字段 类型 描述
1 EMPNO NUMBER(4) 雇员编号
2 ENAME VARCHAR2(10) 表示雇员姓名
3 JOB VARCHAR2(9) 表示工作职位
4 MGR NUMBER(4) 表示一个雇员的领导编号
5 HIREDATE DATE 表示雇佣日期
6 SAL NUMBER(7,2) 表示月薪,工资
7 COMM NUMBER(7,2) 表示奖金或佣金
8 DEPTNO NUMBER(2) 表示部门编号
部门表:表示一个部门的具体信息
DEPT(部门表)
NO 字段 类型 描述
1 DEPTNO NUMBER(2) 部门编号
2 DNAME VARCHAR2(14) 部门名称
3 LOC VARCHAR2(13) 部门位置
奖金表:表示一个雇员的工资及奖金。
BONUS(奖金表)
NO 字段 类型 描述
1 ENAME VARCHAR2(10) 雇员姓名
2 JOB VARCHAR2(9) 雇员工作
3 SAL NUMBER 雇员工资
4 COMM NUMBER 雇员奖金
一个公司是有等级制度,用此表表示一个工资的等级
SALGRADE(工资等级表)
NO 字段 类型 描述
1 GRADE NUMBER 等级名称
2 LOSAL NUMBER 此等级的最低工资
3 HISAL NUMBER 此等级的最高工资
1.3.3查询语法
Select * |列名 from 表名;
1.3.4 别名用法
在查询的结果列中可以使用别名
Select 列名 别名,列名别名,... from emp;
1.3.5 消除重复数据
Select distinct *|列名, ... from emp;
使用distinct
可以消除重复的行,如果查询多列的必须保证多列都重复才能去掉重复
1.3.6 字符串连接查询
查询雇员编号,姓名,工作
编号是:7369的雇员, 姓名是:smith,工作是:clerk
select '编号是:' || empno || '的雇员,姓名是:' || ename || ',工作是:' || job from emp;
字符串的连接使用||
1.3.7 查询中四则运算
查询每个雇员的年薪
select ename, sal*12 from emp;
select ename, sal*12 income from emp;
Sql中支持四则运算+,-,*,/
1.3.8 条件查询
在查询绝大多数都会有条件的限制
语法:select *|列名 from 表名 where 条件
例如:查询工资大于1500的所有雇员
select * from emp
where sal>1500;
1.3.9 非空和空查询
示例:查询每月能得到奖金的雇员
分析:只要字段中存在内容表示不为空,如果不存在内容就是null
,
语法:列名 IS NOT NULL
为空 列名 IS NULL
多个查询条件同时满足之间使用AND
多个查询条件或满足,条件之间使用OR
不满足使用NOT
1.3.10 范围限制
select * from emp where sal between 1500 and 3000;
--Between and等于 sal > =1500 and sal <= 3000
--between and 不仅可以使用在数值之间,也可以用在日期的区间
--在oracle中的查询条件中查询条件的值是区分大小写的
select * from emp where empno in(7369,7499,7521);
--其中的值不仅可以是数值类型也可以是字符串
1.3.11 模糊查询
在常用的站点中经常会有模糊查询,即:输入一个关键字,把符合的内容全部的查询出来,在sql中使用LIKE语句完成。
在LIKE中主要使用以下两种通配符
%
:可以匹配任意长度的内容
_
:可以匹配一个长度的内容
ESCAPE
子句允许查找包含一个或多个通配符的字符串。
例如,表可能包含具有百分比字符的数据,例如折扣值,折旧率。要搜索字符串25%
,可以使用ESCAPE
子句,如下所示:
LIKE '%25!%%' ESCAPE '!'
如果不使用ESCAPE
子句,则Oracle将返回字符串为25
的任何行。
1.3.12 排序
在sql中可以使用ORDER BY对查询结果进行排序
语法:SELECT * |列名 FROM 表名 {WEHRE 查询条件} ORDER BY 列名1 ASC|DESC,列名2...ASC|DESC
分析:ORDER BY 列名 默认的排序规则是升序排列,可以不指定ASC,如果按着降序排列必须指定DESC
注意ORDER BY语句要放在sql的最后执行。
排序 order by 经验:当排序时存在null时就会产生问题 nulls first , nulls last
不需要指定用于排序数据的列名称。如果您愿意,可以使用ORDER BY
子句中列的位置。
请参考下语句 -
SELECT name, credit_limit,address
FROM customers
ORDER BY 2 DESC, 1;
在这个例子中,name
列的位置是1
,credit_limit
列的位置是2
。相当于以下查询语句 -
SELECT name, credit_limit,address
FROM customers
ORDER BY credit_limit DESC, name;
在ORDER BY
子句中,使用这些列位置来指示Oracle对行进行排序。
当使用非NULL
值对混合NULL
进行排序时,Oracle允许指定哪个应该首先出现。
例如,以下语句按升序对state
列进行排序,并首先将NULL
值放置在前面。
SELECT country_id, city, state
FROM
locations
ORDER BY
state ASC NULLS FIRST;
要放置NULL
值在后面,可以使用NULLS LAST
,如下面的语句所示:
SELECT country_id, city, state
FROM
locations
ORDER BY
state ASC NULLS LAST;
ORDER BY
子句可在一列上应用一个函数,例如字符串函数,数学函数等,并按函数的结果对数据进行排序。
例如,以下语句使用ORDER BY
子句中的UPPER()函数来区分客户名称的大小写:
SELECT customer_id, name
FROM customers
ORDER BY UPPER( name );
–查询雇员的工资从低到高
select * from emp order by sal nulls first;
select * from emp order by sal desc nulls last ;
1.3.13 Fetch子句
Oracle数据库标准中没有LIMIT
子句。 然而,自12c
发布以来,它提供了一个类似但更灵活的子句,即行限制子句。
如下所示:
SELECT
product_name,
quantity
FROM
inventories
INNER JOIN products
USING(product_id)
ORDER BY
quantity DESC
FETCH NEXT 5 ROWS ONLY;
注意:上面查询仅能在Orace 12c以上版本中运行。
如果使用的是Oracle 11g及以下版本的,请参考以下语句 -
SELECT
product_name, quantity
FROM
inventories
INNER JOIN products
USING(product_id)
WHERE rownum<=5
ORDER BY quantity DESC;
Oracle FETCH子句语法
以下说明了行限制子句的语法:
[ OFFSET offset ROWS]
FETCH NEXT [ row_count | percent PERCENT ] ROWS [ ONLY | WITH TIES ]
OFFSET子句
OFFSET
子句指定在行限制开始之前要跳过行数。OFFSET
子句是可选的。 如果跳过它,则偏移量为0
,行限制从第一行开始计算。
偏移量必须是一个数字或一个表达式,其值为一个数字。偏移量遵守以下规则:
- 如果偏移量是负值,则将其视为
0
。 - 如果偏移量为
NULL
或大于查询返回的行数,则不返回任何行。 - 如果偏移量包含一个分数,则分数部分被截断。
FETCH子句
FETCH
子句指定要返回的行数或百分比。
为了语义清晰的目的,您可以使用关键字ROW
而不是ROWS
,FIRST
而不是NEXT
。 例如,以下子句的行为和产生的结果相同:
FETCH NEXT 1 ROWS
FETCH FIRST 1 ROW
ONLY | WITH TIES选项
仅返回FETCH NEXT
(或FIRST
)后的行数或行数的百分比。
WITH TIES
返回与最后一行相同的排序键。请注意,如果使用WITH TIES
,则必须在查询中指定一个ORDER BY
子句。如果不这样做,查询将不会返回额外的行。
1.3.14 Oracle Exists运算符
Oracle Exists
运算符是返回true
或false
的布尔运算符。EXISTS
运算符通常与子查询一起使用来测试行的存在:
SELECT
*
FROM
table_name
WHERE
EXISTS(subquery);
如果子查询返回任何行,则EXISTS
运算符返回true
,否则返回false
。 另外,当子查询返回第一行,EXISTS
操作符终止子查询的处理。
NOT EXISTS
运算符与EXISTS
运算符相反。我们经常在子查询中使用NOT EXISTS
运算符来从一个数据中减去另一组数据。
看一下使用NOT EXISTS
运算符的以下语句:
SELECT
*
FROM
table_name
WHERE
NOT EXISTS (subquery);
如果子查询不返回任何行,则NOT EXISTS
运算符返回true
。 否则,它返回false
。
请注意,如果子查询返回任何具有
NULL
值的行,则NOT EXISTS
运算符将返回false
。
1.3.15 Any/All
Oracle ANY
运算符用于将值与子查询返回的值或结果集列表进行比较。下面举例说明ANY
运算符与列表或子查询一起使用时的语法:
operator ANY ( v1, v2, v3)
operator ANY ( subquery)
SQL
在这个语法中:
ANY
运算符前面必须有一个运算符,例如:=
,!=
,>
,>=
,<
,<=
。- 列表或子查询必须用圆括号包围。
使用ANY
运算符将值与列表进行比较时,Oracle将初始条件扩展到列表的所有元素,并使用OR
运算符将它们组合,如下所示:
SELECT
*
FROM
table_name
WHERE
c > ANY (
v1,
v2,
v3
);
Oracle将上述查询转换为以下内容:
SELECT
*
FROM
table_name
WHERE
c > v1
OR c > v2
OR c > v3;
如果使用ANY
运算符将一个值与子查询返回的结果集进行比较,则Oracle使用EXISTS运算符将查询转换为等效的查询,而不使用ANY
运算符。
Oracle ALL
操作符用于将值与子查询返回的值列表或结果集进行比较。
以下显示了与列表或子查询一起使用的ALL
运算符的语法:
operator ALL ( v1, v2, v3)
operator ALL ( subquery)
在这个语法中,
- ALL运算符前面必须有一个运算符,例如:
=
,!=
,>
,>=
,<
,<=
,后跟一个列表或子查询。 - 列表或子查询必须用圆括号包围。
使用ALL
运算符将值与列表进行比较时,Oracle将初始条件扩展到列表的所有元素,并使用AND
运算符将它们组合在一起,如下所示:
SELECT
*
FROM
table_name
WHERE
c > ALL (
v1,
v2,
v3
);
-- 以上语句转换为 ALL 运算符后
SELECT
*
FROM
table_name
WHERE
c > v1
AND c > v2
AND c > v3;
1.4 函数
1.4.1 字符函数
--接收字符输入返回字符或者数值,dual是伪表
--1. 把小写的字符转换成大小的字符
upper('smith')
--2. 把大写字符变成小写字符
lower('SMITH')
--3. 把首字符大写
initcap('smith')
--4. 字符串的连接可以使用concat可以使用“||”建议使用“||”
concat('hello', 'world')
--5. 字符串的截取,使用substr,第一个参数是源字符串,第二个参数是开始索引,第三个参数长度,开始的索引使用1和0效果相同
substr('hello', 1,3)
--6. 获取字符串的长度
length('hello')
--7. 字符串替换,第一个参数是源字符串,第二个参数被替换的字符串,第三个是替换字符串
replace('hello', 'l','x')
1.4.2 数值函数
--1. 四舍五入函数:ROUND(数值),ROUND(数值,位数)默认情况下ROUND四舍五入取整,可以自己指定保留的位数。
--2. 取整:TRUNC(),默认全部去掉小数,也可以指定保留的位数
--3. 取余数MOD()
1.4.3 日期函数
Oracle中提供了很多和日期相关的函数,包括日期的加减,在日期加减时有一些规律
日期 – 数字 = 日期
日期 + 数字 = 日期
日期 – 日期 = 数字
-
范例:查询雇员的进入公司的周数。
分析:查询雇员进入公司的天数(sysdate – 入职日期)/7就是周数
select ename,round((sysdate-hiredate)/7) from emp;
-
获得两个时间段中的月数:MONTHS_BETWEEN()
select ename,round(months_between(sysdate-hiredate)) from emp;
-
获得几个月后的日期:ADD_MONTHS()
范例:求出三个月后的日期
select add_months(sysdate,3) from dual;
1.4.4 转换函数
- TO_CHAR:字符串转换函数
范例:查询所有的雇员将将年月日分开,此时可以使用TO_CHAR函数来拆分
拆分时需要使用通配符
年:y, 年是四位使用yyyy
月:m, 月是两位使用mm
日:d, 日是两位使用dd
select empno,ename,to_char(hiredate,'yyyy-mm-dd') from emp;
--结果
7934 MILLER 1982-01-23
7902 FORD 1981-12-03
7900 JAMES 1981-12-03
7839 KING 1981-11-17
7654 MARTIN 1981-09-28
7844 TURNER 1981-09-08
7782 CLARK 1981-06-09
7698 BLAKE 1981-05-01
7566 JONES 1981-04-02
7521 WARD 1981-02-22
7499 ALLEN 1981-02-20
7369 SMITH 1980-12-17
在结果中10以下的月前面被被补了前导零,可以使用fm去掉前导零
select empno,ename,to_char(hiredate,'fmyyyy-mm-dd') from emp;
--结果
7369 SMITH 1980-12-17
7499 ALLEN 1981-2-20
7521 WARD 1981-2-22
7566 JONES 1981-4-2
7654 MARTIN 1981-9-28
7698 BLAKE 1981-5-1
7782 CLARK 1981-6-9
7839 KING 1981-11-17
7844 TURNER 1981-9-8
7900 JAMES 1981-12-3
7902 FORD 1981-12-3
7934 MILLER 1982-1-23
TO_CHAR还可以给数字做格式化
范例:把雇员的工资按三位用“,”分隔,在oracle中“9”代表一位数字
select ename,to_char(sal,'99,999') from emp;
--结果
SMITH 800
ALLEN 1,600
WARD 1,250
JONES 2,975
MARTIN 1,250
BLAKE 2,850
CLARK 2,450
KING 5,000
TURNER 1,500
JAMES 950
FORD 3,000
MILLER 1,300
如果在钱的前面加上国家的符号可以使用“$”代表是美元,如果要使用本地的钱的单位使用“L” :
-
TO_NUMBER:数值转换函数
TO_NUMBER可以把字符串转换成数值
select to_number('10') from dual;
-
TO_DATE:日期转换函数
TO_DATE可以把字符串的数据转换成日期类型
select TO_DATE('1985-04-22', 'yyyy-mm-dd') from dual; --结果 22-4月 -85
1.4.5 通用函数
-
空值处理nvl
范例:查询所有的雇员的年薪
select ename,sal*12+comm from emp; --结果 SMITH ALLEN 19500 WARD 15500 JONES MARTIN 16400 BLAKE CLARK KING TURNER 18000 JAMES FORD MILLER
我们发现很多员工的年薪是空的,原因是很多员工的奖金是null,null和任何数值计算都是null,这时我们可以使用nvl来处理。
select ename,sal*12+nvl(comm,0) from emp; --结果 SMITH 9600 ALLEN 19500 WARD 15500 JONES 35700 MARTIN 16400 BLAKE 34200 CLARK 29400 KING 60000 TURNER 18000 JAMES 11400 FORD 36000 MILLER 15600
-
decode函数
该函数类似if…else if…esle
语法:DECODE(col/expression, [search1,result1],[search2, result2]....[default]) Col/expression:列名或表达式 Search1,search2...:用于比较的条件 Result1, result2...:返回值
如果col/expression和Searchi匹配就返回resulti,否则返回default的默认值
select ename, decode( job, 'CLERK','业务员', 'SALESMAN','销售', 'PRESIDENT','总裁', 'MANAGER','分析员', 'MANAGER','经理', '无业' ) from emp; --结果 SMITH 业务员 ALLEN 销售 WARD 销售 JONES 分析员 MARTIN 销售 BLAKE 分析员 CLARK 分析员 KING 总裁 TURNER 销售 JAMES 业务员 FORD 无业 MILLER 业务员
-
case when
CASE expr WHEN comparison_expr1 THEN return_expr1 [WHEN comparison_expr2 THEN return_expr2 WHEN comparison_exprn THEN return_exprn ELSE else_expr] END
select t.empno, t.ename, case when t.job = 'CLERK' then '业务员' when t.job = 'MANAGER' then '经理' when t.job = 'ANALYST' then '分析员' when t.job = 'PRESIDENT' then '总裁' when t.job = 'SALESMAN' then '销售' else '无业' end from emp t --结果 7369 SMITH 业务员 7499 ALLEN 销售 7521 WARD 销售 7566 JONES 经理 7654 MARTIN 销售 7698 BLAKE 经理 7782 CLARK 经理 7839 KING 总裁 7844 TURNER 销售 7900 JAMES 业务员 7902 FORD 分析员 7934 MILLER 业务员
1.4.6 聚合函数
-
统计记录数count()
不建议使用count(*),可以使用一个具体的列以免影响性能。
-
最小值查询min()
-
最大值查询max()
-
查询平均值avg()
-
求和函数sum()
1.5 集合操作
1.5.1 并集
UNION
运算符是一个集合运算符,它将两个或多个SELECT语句的结果集组合到一个结果集中。
UNION
运算符删除(消除)重复的行 UNION ALL
保留了重复的行
以下说明了组合两个查询的结果集的UNION
运算符的语法:
SELECT
column_list_1
FROM
T1
UNION
SELECT
column_list_1
FROM
T2;
在此声明中,column_list_1
和column_list_2
必须具有相同顺序的相同列数。 另外,对应列的数据类型必须是相同的数据类型组,例如数字或字符。
SELECT
column_list
FROM
T1
UNION ALL
SELECT
column_list
FROM
T2;
1.5.2 交集
INTERSECT L
Oracle INTERSECT
运算符比较两个查询的结果,并返回两个查询输出的不同行。
以下语句显示了INTERSECT
运算符的语法:
SELECT
column_list_1
FROM
T1
INTERSECT
SELECT
column_list_2
FROM
T2;
与UNION运算符相似,使用INTERSECT
运算符时必须遵循以下规则:
- 两个查询中列的数量和顺序必须相同。
- 相应列的数据类型必须处于相同的数据类型组中,例如数字或字符。
1.5.3 差集
MINUS
Oracle MINUS
运算符比较两个查询,并返回第一个查询中但不是第二个查询输出的行。 换句话说,MINUS
运算符从一个结果集中减去另一个结果集。
以下说明Oracle MINUS
运算符的语法:
SELECT
column_list_1
FROM
T1
MINUS
SELECT
column_list_2
FROM
T2;
与UNION和INTERSECT操作符类似,上面的查询必须符合以下规则:
- 列数和它们的顺序必须匹配一致。
- 相应列的数据类型必须处于相同的数据类型组中,例如数字或字符。