一、基本查询(DQL)

1、查询结构

(5)SELECT * |列名|表达式      -- 表示表的所有列名称;多个列或者多个表达式用逗号分隔 

(1)FROM 表名|结果集 -- 查看的对象为表或者结果集

(2)WHERE 条件 -- 多个条件用and/or/not 连接

(3)GROUP BY 列名 -- 多个列用逗号分隔,分组

(4)HAVING 条件 -- 一般为聚合函数表达式,分组后过滤,前面要有GROUP BY,多个表达式 AND/OR/NOT 连接

(6)ORDER BY 列名 [ ASC / DESC ] -- ASC 升序(默认),DESC 降序

2、条件查询
  • 运算符

> 、>= 、<  、<= 、 =  、<=> 、 !=  、<>

  • 逻辑运算符

AND/OR/NOT

  • 模糊运算符
  • LIKE :字符匹配操作可以使用通配符​​%​​​ 和​​_​​​ ,​​%​​​ 代表零个或多个字符,​​_​​ 代表任意一个字符
  • BETWEEN AND:查询包含在指定区间内(包含边界)的 值
  • NOT BETWEEN AND:查询不在范围内的数据
  • IN/NOT IN/NOT EXISTS:如果查询语句使用了NOT IN,那么对内外表都进行全表扫描,没有用到索引;而NOT EXISTS的子查询依然能用到表上的索引。所以无论哪个表大,用NOT EXISTS都比NOT IN要快

--查询名字中包含'A'
SELECT * FROM emp
WHERE ENAME LIKE '%A%';

--按时间查询
SELECT * FROM emp
WHERE HIREDATE BETWEEN DATE '1980-01-01' AND DATE'1982-01-01';

3、子查询
  • 单行子查询:不向外部返回结果,或者只返回一行结果

SELECT * FROM emp 
WHERE SAL >(SELECT SAL FROM EMP WHERE ENAME = 'FORD')

  • 多行子查询:向外部返回零行、一行或者多行结果

SELECT * FROM emp 
WHERE (DEPTNO,SAL) IN (SELECT DEPTNO,MAX(SAL) FROM EMP GROUP BY DEPTNO)

4、多表查询 (结果集增加列)
  • 内连接
  • 隐式内连接接

SELECT * FROM emp E,DEPT D WHERE E.DEPTNO = D.DEPTNO;

  • 显式内连接

SELECT * FROM emp E INNER JOIN DEPT D ON E.DEPTNO = D.DEPTNO;

  • 左外连接
  • 隐式左外连接

SELECT * FROM emp E,DEPT D WHERE E.DEPTNO = D.DEPTNO(+);

  • 显式左外连接

SELECT * FROM emp E LEFT JOIN DEPT D ON E.DEPTNO = D.DEPTNO;

  • 右外连接
  • 隐式左外连接

SELECT * FROM emp E,DEPT D WHERE E.DEPTNO(+) = D.DEPTNO;

  • 显式左外连接

SELECT * FROM emp E RIGHT JOIN DEPT D ON E.DEPTNO = D.DEPTNO;

  • 交叉连接(产生笛卡尔积)
  • 隐式交叉连接

SELECT * FROM emp,DEPT

  • 显式交叉连接

SELECT * FROM emp E CROSS JOIN DEPT D

  • 全外连接

SELECT * FROM emp E FULL JOIN DEPT D ON E.DEPTNO = D.DEPTNO;

5、集合运算 (结果集增加行)

<!--查询所返回的列数以及列的类型必须匹配,列名可以不同,只有UNION ALL不会去重。其他三个都需要排序后去重,性能比较差-->

  • 并集运算:将两个查询结果进行合并
  • UNION(去重,排序)

SELECT * FROM emp WHERE DEPTNO = 10
UNION
SELECT * FROM emp WHERE SAL <2000;

  • UNION ALL(不去重,不排序)

SELECT * FROM emp WHERE DEPTNO = 10
UNION ALL
SELECT * FROM emp WHERE SAL <2000;

  • 交集运算(两者共有部分)

  • INTERSECT

SELECT * FROM emp WHERE SAL>1500
INTERSECT
SELECT * FROM emp WHERE DEPTNO =20;

  • 差集运算(前者有后者无)
  • MINSU

SELECT * FROM emp WHERE DEPTNO =20 
MINUS
SELECT * FROM emp WHERE SAL>1500

6、伪列
  • ROWID
  • 表中的每一行在数据文件中都有一个物理地址,ROWID伪列返回的就是该行的物理地址
  • 使用ROWID可以快速的定位表中的某一行
  • ROWID值可以唯一的标识表中的一行

-- 去重,删除重复数据
DELETE FROM EMP E WHERE ROWID NOT IN (SELECT MIN(ROWID) FROM EMP E GROUP BY EMPNO);

  • ROWNUM
  • 在查询的结果集,ROWNUM为结果集中每一行标识一个行号,第一行返回1,第二行返回2,以此类推
  • 通过ROWNUM伪列可以限制查询结果集中返回的行数,可以实现分页查询
  • rownum 必须从1开始查询

--查询emp表第3-7列数据
SELECT ENAME,SAL,DEPTNO,RN
FROM
(SELECT E.*,ROWNUM RN FROM emp E WHERE ROWNUM<8)
WHERE RN >2;

二、数据定义(DDL)

<!--数据定义语言(DDL),包括CREATE(创建)命令、ALTER(修改)命令、DROP(删除对象)、TRUNCATE(删除表数据)命令等。-->

1、数据类型

常见类型

示例

CHAR(length)

存储固定长度的字符串。参数length指定了长度,如果存储的字符串长度小于length,用空格填充。默认长度是1,最长不超过2000字节

VARCHAR2(length)

存储可变长度的字符串。length指定了该字符串的最大长度。默认长度是1,最长不超过4000字符

NUMBER(p,s)

存储可变长度的字符串。length指定了该字符串的最大长度。默认长度是1,最长不超过4000字符。p是总长度,s是小数,整数部分长度是p-s。

DATE

存储日期和时间,存储纪元、4位年、月、日、时、分、秒,存储时间从公元前4712年1月1日到公元后4712年12月31日

NULL

在查询条件中NULL值用IS NULL作条件,非NULL值用 IS NOT NULL做条件 <br/>空值跟任何值进行算术运算,得到的结果都为空值 <br/>空值跟任何值进行关系运算,得到的结果都为不成立 <br/>空值不参与任何聚合运算 排序的时候,空值永远是最大的

2、CREATE(创建)命令

-- 语法格式
create table 表名 (列名1 数据类型, 列名2 数据类型,...);

-- 加注释
comment on table 表名 is '表注释名';
comment on table 表名.列名1 is '字段注释名';
-- 创建一张学生表
create table student_info --学生信息表
(id number(4) primary key --主键
,sno number(4) --学号
,sname varchar2(20) not null --姓名
,sex varchar2(2) check(sex = '男'or sex = '女') --性别
,graduated_year number(4) --毕业年龄
,major varchar2(40) --专业
,province varchar2(20) --省份
,dnum number constraint pk_1 references emp(empno) --外键
);

3、ALTER 更改表结构

<!--修改的列没有数据时,可以随便更改类型;修改的列有数据时,只能在同一种类型上增加长度-->

-- 语法格式
-- 修改列数据类型
alter table 表名 modify 列名 新的数据类型;
alter table student_info modify sno varchar2(20);
-- 修改表名
alter table 表名 rename to 新表名;
alter table sutdent_info to student_info_new;
-- 修改列名
alter table 表名 rename column 旧列名 to 新列名;
alter table student_info rename column sno to snumber;
-- 增加列
alter table 表名 add 列名 数据类型;
alter table student_info add age number(3);
-- 删除列
alter table 表名 drop column 列名;
alter table student_info drop column sex;

4、DROP 删除表对象

-- 语法格式
drop table 表名;
drop table student_info;

5、TRUNCATE(对象是表)删除表数据

<!--清空整张表数据, 不会将清除的数据写入日志,不能跟where-->

-- 语法格式
truncate table 表名;
truncate table student_info;

6、表的约束

<!--表的约束是Oracle数据库中应用在表数据上的一系列强制性规则。当向已创建的表中插入数据或修改表中的数据时,必须满足表的完整性约束所规定的条件。例如,学生的性别必须是“男”或“女”,各个学生的学号不得相同等。在设计表的结构是,应该充分考虑在表上需要施加的完整性约束。表的完整性约束既可以在创建表时制定,也可以在表创建之后再指定。可以对一个或多个字段进行约束。-->

分类

  • PRIMARY KEY:主键约束
  • FOREIGN KEY:外键约束
  • CHECK:检查约束
  • UNIQUE:唯一约束
  • NOT NULL:非空约束

创建命令

<!--一张表只有一个主键,主键非空且唯一-->

<!--约束不能修改,只能删除重建-->

--添加主键约束
alter table 主表名 add constraint 约束名 primary key(列名1[,列名2...])
alter table student_info add constraint p_sno primary key(sno);
--添加外键约束
alter table 主表名 add constraint 约束名 foreign key(列名1[,列名2...]) references 从表名(列名1[,列名2...])
--添加CHECK约束
ALTER TABLE 表名 ADD CONSTRAINT 约束名 CHECK(条件)
--添加唯一约束
ALTER TABLE 表名 ADD CONSTRAINT 约束名 UNIQUE(列名)
--添加非空约束
ALTER TABLE 表名 MODIFY 列名 NOT NULL

7、创建分区表

create table students_info(
id number(4) primary key,
name varchar2(30),
dnum number,
datatime date )
partition by range(datatime)
(partition part1 values less than(to_date('1999-4-1','yyyy/mm/dd')),
partition part2 values less than(to_date('1999-4-2','yyyy/mm/dd')),
partition part3 values less than(to_date('2000-4-2','yyyy-mm-dd'))
)
--添加分区
alter table students_info add partition part4 values less than(to_date('2000-4-3','yyyy/mm/dd'));

--查询分区数据
select * from students_info partition(part4);

8、创建自增序列

<!--因为是首次查询序列的当前值,内存中之前并没有缓存序列的任何值,所以需要先查询 一下序列的下一个值(此时,Oracle会自动缓存已查询的序列值),再查询序列的当前值。-->

create sequence SEQ_ID
minvalue 1 ---最小者=值
maxvalue 99999999 ---最大值
start with 1 -- 从1开始计数
increment by 1 -- 每次加几个
nocache -- cache/nocache:nocache不缓存。cache缓存。开启缓存,效率高
;
select SEQ_ID.currval from dual;----查看序列当前值
select SEQ_ID.nextval from dual;--查看序列当前下个值,每次运行语句都会增加

9、索引
  • 类型:唯一索引(主键、唯一)、组合索引、基于函数的索引、反向键索引、位图索引
  • 创建索引

--语法结构
CREATE [UNIQUE] INDEX index_name ON table_name(column_name[,column_name…])

  • 删除索引

--语法结构
DROP INDEX 索引名

  • 索引失效场景

- 没有查询条件,或者查询条件没有建立索引 
- 隐式转换
- 查询条件中有or
- 对索引列进行运算、使用内部函数
- like查询是以%开头
- not in、not exists

  • 优点:加快检索速度;减少分组合排序的时间;唯一性;
  • 缺点:占用空间;占用时间;

三、数据操纵(DML)

*数据操纵语言(DML),包括INSERT(插入)命令、UPDATE(更新)命令、DELETE(删除)命令、SELECT(查找)命令等。对数据表进行DML操作后,一定要主要对数据进行提交(commit)或者回滚(rollback)*

1.INSERT INTO 插入数据到表中

--语法格式
INSERT INTO 表名(列名1,列名2,……) VALUES (值1,值2……)
INSERT INTO student_2(ename,age,birthday) VALUES ('张三',20,date'2000-12-01');
INSERT INTO student_2(ename,age,birthday) VALUES ('李四',22,date'1998-12-01');

2.UPDATE 更新表数据

--语法格式
UPDATE 表名 SET 列名1=值, 列名2=值,…… WHERE 条件

3.DELETE 删除表数据

--语法格式
DELETE FROM 表名 WHERE 条件; 删除的数据可以从日志中找回

四、函数

1、字符函数

表达式

示例

CONCAT(x,y)

连接字符串x和y

LENGTH(x)

返回x的长度

LOWER(x)

x转换为小写

UPPER(x)

x转换为大写

TRIM(x)

去掉字符串两端的多余的空格

REPLACE(x,old,new)

在x中查找old,并替换为new

SUBSTR(x,start[,length])

返回x的字串,从staart处开始,截取length个字符,缺省length,默认到结尾

2、数字函数

表达式

示例

ABS(x)

x绝对值<br/>ABS(-3)=3

MOD(x,y)

x除以y的余数<br/>MOD(8,3)=2

POWER(x,y)

x的y次幂<br/>POWER(2,3)=8

ROUND(x[,y])

x在第y位四舍五入<br/>ROUND(3.456,2)=3.46

TRUNC(x[,y])

x在第y位截断,直接截取,不四舍五入<br/>TRUNC(3.456,2)=3.45

3、日期函数

表达式

示例

add_months(d,n)

在某一个日期d上,加上指定的月数n,返。d表示日期,n表示要加的月数<br/>select sysdate,add_months(sysdate,3) from dual

last_day(d)

返回指定日期当月的最后一天<br/>select sysdate,last_day(sysdate) from dual;

round(d,'fmt')

返回一个以fmt为格式的四舍五入日期值,d是日期,fmt是格式模型。默认fmt为DDD,即月中的某一天

trunc(d,'fmt')

对日期的操作,TRUNC与ROUND非常相似,只是不对日期进行舍入,直接截取到对应格式的第一天

--例
select sysdate, --22/4/25 12:14:34
round(sysdate), --22/4/26
round(sysdate,'day'), --22/4/24
round(sysdate,'month'), --22/5/1
round(sysdate,'year') --22/1/1
from dual;

4、转换函数
  • 转换为字符串:to_char

SELECT TO_CHAR(SYSDATE,'YYYYMMDD')
FROM dual;


  • 转换为日期:to_date

SELECT TO_DATE('20170731123245','YYYYMMDD HH24:MI:SS')
FROM dual;

  • 转换为数字:to_number

SELECT TO_NUMBER('123456')
FROM dual;

5、其他常用函数
  • nvl(x,value) --如果x为空,返回value,否则返回x。

SELECT ENAME,COMM,NVL(COMM,0)+100 
FROM emp
WHERE SAL<2000;

  • nvl2(x,value1,value2) --如果x非空,返回value1,否则返回value2

SELECT ENAME,NVL2(COMM,COMM+100,200)
FROM emp;

  • decode(列|表达式,值1,value1,值2,value2,...,默认值)

<!--当参数的值为判断值1,则返回value1……当参数的值匹配不到时,则返回默认值-->

--例
SELECT E.ENAME,
DECODE(E.JOB,
'CLERK','业务员',
'SALESMAN','销售员',
'MANAGER','经理',
'ANALYST','分析员',
'PRESIDENT','总裁') FROM emp E

  • case when end

<!--适用于多条件判断-->

-- 第一种语法
CASE 参数
WHEN 判断值1 THEN 返回值1
WHEN 判断值2 THEN 返回值2
……
ELSE 默认值 END
--例
Select E.Ename,
case e.job
WHEN 'CLERK' THEN'业务员'
WHEN 'SALESMAN' THEN'销售员'
WHEN 'MANAGER' THEN'经理'
WHEN 'ANALYST' THEN'分析员'
WHEN 'PRESIDENT' THEN'总裁'
END
FROM EMP E

--第二种语法
CASE
WHEN 条件1 THEN 返回值1
WHEN 条件2 THEN 返回值2
……
ELSE 默认值 END
--例
select e.*,
case
when sal>3000 then '工资很高'
when sal>1000 then '工资一般'
else '工资很低'
end
from emp e

  • 行列转换

--创建表 emp014
create table emp014(id number,q number,amt number)
id q AMT
01 1 100
01 4 100
02 1 200
01 2 110
02 2 150
02 3 100
01 3 130
02 4 200
--创建表 emp015
create table emp015(y number,q1 number,q2 number,q3 number,q4 number)
insert into emp015( Y,Q1,Q2, Q3, Q4)values(01,100,110,130,100);
insert into emp015( Y,Q1,Q2, Q3, Q4)values(02 ,200,150,100,200);
--emp014 转 emp015 
with aa as
(select id y,
max(case when q =1 then amt end) q1,
max(case when q =2 then amt end) q2,
max(case when q =3 then amt end) q3,
max(case when q =4 then amt end) q4
from emp014
group by id)
select * from aa
--emp015 转 emp014
with aa as
(select id,
max(case when q=1 then amt end) as q1,
max(case when q=2 then amt end) as q2,
max(case when q=3 then amt end) as q3,
max(case when q=4 then amt end) as q4
from emp014
group by id )
select id , 1 as q1,q1 as amt
from aa union all
select id , 2 as q1,q2 as amt
from aa union all
select id , 3 as q1,q3 as amt
from aa union all
select id , 4 as q1,q4 as amt
from aa

6、分析函数
  • 分析函数与聚合函数不同,聚合函数用group by分组,每个分组返回一个统计值,而分析函数采用partition by 分组,并且每组每行都可以返回一个统计值
  • 函数()OVER(PARTITION BY 字段 ORDER BY 字段 [ASE/DESC])

--求每个部门工资高于部门平均工资的员工数量
SELECT DEPTNO,COUNT(*)
FROM (SELECT E.*,
AVG(E.SAL) OVER(PARTITION BY E.DEPTNO) AVG
FROM EMP E) A
WHERE SAL>AVG
GROUP BY DEPTNO;

  • MAX(),MIN(),SUM(),AVG(),COUNT() --加了ORDER BY 是累计求值
  • 排序分析函数 100 90 90 80 70
  • ROW_NUMBER() --派号码排序, 1 2 3 4 5
  • RANK() --跳跃排序派号码 1 2 2 4 5
  • DENSE_RANK() --不跳跃排序派号码 1 2 2 3 4

-- 各部门工资排名前3的员工的所有信息
SELECT *
FROM (SELECT E.*,
DENSE_RANK()OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RN
FROM emp E)
WHERE RN<4

  • 聚类分析函数
  • MAX(column_name)OVER()
  • MIN(column_name)OVER()
  • SUM(column_name)OVER()
  • AVG(column_name)OVER()
  • COUNT(column_name)OVER()

--加了ORDER BY 是累计求值
--例
SELECT T.*,
SUM(SAL)OVER() D_SUM_SAL,
SUM(SAL)OVER(PARTITION BY DEPTNO ORDER BY EMPNO DESC) SUM_SAL
FROM emp T;

  • 最大值、最小值分析函数

--语法格式
MAX()/MIN() KEEP (DENSE_RANK FIRST/LAST ORDER BY )
--查询工资最大、最小员工
SELECT
MAX(EMPNO)KEEP(DENSE_RANK FIRST ORDER BY SAL) MIN_SAL,
MAX(EMPNO)KEEP(DENSE_RANK LAST ORDER BY SAL) MAX_SAL
FROM emp T;

  • 按层次查询
  • 平均分配,如果不能平均分配,则较小层次分配额外的行,并且各个层次能放的行数最多相差1

SELECT T.*,NTILE(5)OVER(ORDER BY SAL DESC) N FROM emp T

  • 位移分析函数

--LAG(取值字段,N)OVER(ORDER BY  排序字段)    --N 表示步长,表示取前 N 个的结果
--LEAD(取值字段,N)OVER(ORDER BY 排序字段) --N 表示步长,表示取后 N 个的结果
--例1
SELECT T.*,
LAG(SAL,1,0)OVER(ORDER BY SAL) A,
LEAD(SAL,2,1)OVER(ORDER BY SAL) B,
FROM emp T;

--例2
SELECT T.*,
LAG(SAL,1)OVER(PARTITION BY DEPTNO ORDER BY SAL) C,
LEAD(SAL,1)OVER(PARTITION BY DEPTNO ORDER BY SAL) D
FROM emp T;