【Oracle】基础知识查漏补缺

前言

该文章内容不是学习oracle的基础知识,而是在大致了解oracle的基础知识上看我自己还有什么不知道或者不明白的地方,有兴趣的小伙伴可以在网上找找李兴华的oracle培训资料。

SQL简介

SQL 功能强大,概括起来,它可以分成以下几组:

· DML(Data Manipulation Language,数据操作语言) —— 指的是实现数据库的查询与更新操作,其中针对于 数据库的查询有部分人员会将其称为 DQL,因为最麻烦的部分就是查询。

· DDL(Data Definition Language,数据定义语言) —— 定义数据库对象,例如:在一些系统设计人员的工作里 面需要进行数据表的定义。

· DCL(Data Control Language,数据控制语言) —— 控制用户的操作权限,一般由 DBA 负责。

 

简单查询

对于重复的数据是有一个基本的原则:只有在所有列的数据都重复的情况下才叫 做重复数据。

SELECT DISTINCT ename,job FROM emp 

“||”的连接符,可以进行数据的连接。

SELECT '编号:' || empno || '、姓名:' || ename || '、工资:' || sal info FROM emp 

 

IN查询

对于 IN 操作而言是针对于基数的判断,如果说此时在使用 NOT IN 的时候基数里面包含了 NULL,那么所有满足

的数据都不会被显示。
范例:观察程序,在 IN 之中使用 NULL —— 现在没有任何的影响

SELECT * FROM emp WHERE empno IN (7369,7566,7839,NULL) ;

范例:观察程序,在 NOT IN 之中使用 NULL

SELECT * FROM emp WHERE empno NOT IN (7369,7566,7839,NULL) ;

不满足的原因是数据库自身的保护机制,避免大数据所带来的问题

模糊查询

字段 LIKE 匹配关键字,而在进行关键字匹配的时候有两个符号标记:

|- “_”:匹配任意一个字符;

|- “%”:匹配 0 个、1 个或多个任意字符。

范例:查询所有姓名第二个字母以 A 开头的所有雇员

SELECT * FROM emp WHERE ename LIKE '_A%' ;

 

SQL执行顺序

自定义输入数据

要查询的数据表名称由用户输入
SELECT * FROM &tablename 

利用替代变量输入雇员姓名
SELECT * FROM emp WHERE ename=UPPER('&name') ;

  

字符串函数

  • UPPER()、LOWER()
  • 首字母大写,其余字母小写:字符串 initcap(字符串 | 列)

    将每一位雇员姓名的首字母大写,其余字母小写
    SELECT INITCAP(ename) FROM emp ;
  • 取得字符串长度:数字 LENGTH(字符串 | 列)
  • 替换指定字符串的内容:字符串 REPLACE(字符串 | 列,要替换的内容,新的内容)
替换数据列 
SELECT ename,REPLACE(ename,'A','_') FROM emp ;
  • 字符串截取操作:
    • 由指定位置截取到结尾:字符串 SUBSTR(字符串 | 数据列,截取开始索引);
    • 指定截取的开始和结束位置:字符串 SUBSTR(字符串 | 数据列,截取开始索引,截取结束索引);
SELECT SUBSTR('hello world',0,5) FROM dual ;
SELECT SUBSTR('hello world',1,5) FROM dual ;
以上俩个结果一致,实际上在 Oracle 之中,字符串的索引下标是从 1 开始的(程序是从 0 开始的),但是为了考虑到程序人员的使用习惯, 所以即使设置了 0,那么也表示从 1 开始,这一点会由 Oracle 自己进行处理。
  • 去掉左右空格函数:字符串 TRIM(字符串 | 列)

    截取每一位雇员姓名的后三位字母
    SELECT ename,SUBSTR(ename,LENGTH(ename)-2) FROM emp ;
    SELECT ename,SUBSTR(ename,-3) FROM emp ;

数字函数

  • 四舍五入函数:数字 ROUND(数字 | 列 [,保留小数位])
SELECT ROUND(9615.7652) ,               ➡️9616
ROUND(9615.7652,2),                         ➡️9615.77
ROUND(9615.7652,-2),                        ➡️9600
ROUND(-15.5)                                     ➡️-16
FROM dual ;
  • 截取小数函数:数字 TRUNC(数字 | 列 [,保留小数位])
SELECT ROUND(9615.7652) ,               ➡️9615
ROUND(9615.7652,2),                         ➡️9615.76
ROUND(9615.7652,-2),                        ➡️9600
ROUND(-15.5)                                     ➡️-15
FROM dual ;
  • 求模:数字 MOD(数字1| 列1,数字2| 列2)
求余数
SELECT MOD(10,3) FROM dual ;

  

日期函数

取得当前的系统日期时间,为此在 Oracle 里面提供有两个伪列(是不存在表中的列,但是却可以直接使用的列):SYSDATE、SYSTIMESTAMP

  • 计算两个日期之间所经历的月数:数字 MONTHS_BETWEEN(日期 1 | 列 1,日期 2 | 列 2)
计算每一位雇员到今天为止雇佣的年数
SELECT ename,MONTHS_BETWEEN(SYSDATE,hiredate) , TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12)
FROM emp ;
  • 加上指定月之后的日期:日期 ADD_MONTHS(日期 | 列 ,月数)
要求计算出每一位雇员到今天为止雇佣的年限(理解)
A、 例如:今天是 2014 年 08 月 12 日,CLARK 的雇佣日期是:1981 年 06 月 09 日 
B、 到今天 CLARK 已经在公司服务了:33 年、02 月、03 天
SELECT ename,hiredate,
TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)/12) year , TRUNC(MOD(MONTHS_BETWEEN(SYSDATE,hiredate),12)) months ,
TRUNC(SYSDATE - ADD_MONTHS(hiredate,MONTHS_BETWEEN(SYSDATE,hiredate))) day
FROM emp ;
  • 求出指定的下一个一周时间数的日期:日期 NEXT_DAY(日期 | 列,一周时间数)
计算下一个星期二
SELECT NEXT_DAY(SYSDATE,'星期二') FROM dual ;
  • 求出指定日期所在月的最后一天日期:日期 LAST_DAY(日期 | 列)
查询出在每个雇员雇佣所在月倒数第二天雇佣的全部雇员信息
SELECT ename,hiredate,LAST_DAY(hiredate)-2 
FROM emp
WHERE LAST_DAY(hiredate)-2=hiredate ;

  

转换函数

  • 转字符串数据:字符串 TO_CHAR(数字 | 日期 | 列,转换格式)
拆分日期数据
SELECT TO_CHAR(SYSDATE,'yyyy') year , 
TO_CHAR(SYSDATE,'mm') months , 
TO_CHAR(SYSDATE,'dd') day
FROM dual ;
  • 转日期数据:日期 TO_DATE(字符串,转换格式)
  • 转数字类型:数字 TO_NUMBER(字符串,转换格式)

通用函数

  • 处理 null 数据:数字 NVL(列 | 数据,默认值)
在数据库之中,null 与任何的数据进行数 学计算其结果都是 null,那么如果遇到了 null 应该按照数字 0 来处理,所以就可以使用 NVL()函数。
SELECT ename,sal,comm,(sal+NVL(comm,0))*12 FROM emp ;
  • 多数据判断:数据 DECODE(字段 | 数据,判断数据 1,显示数据 1,判断数据 2,显示数据 2,... [默认显示])
将所有雇员的职位数据变为中文
SELECT ename,job , DECODE(job,'CLERK','办事员','SALESMAN','销售','MANAGER','经理','ANALYST','分析员','PRESIDENT','总裁','未
处理')

  

多表查询 

将 emp 表(14行数据)和 dept(4行数据) 表实现多表查询
SELECT * FROM emp ,dept ;

执行结果会发现,返回结果有56条数据,为什么呢?出现这样的结果主要是由于数据库的数学公式所导致的,这是两个集合的“积”,而这种积在数据库之中被称为“笛卡尔积”。

如何去消除掉 这样的“笛卡尔积”呢?唯一的方案就是使用关联字段。

不推荐使用的关联方式:

SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc
FROM emp e , dept d
WHERE e.deptno=d.deptno ;

虽然消除掉了显示的笛卡尔积,但是整个运算执行过程非常的缓慢。

对于多表查询来讲其有两种表的连接方式:

  • 内连接:也被称为等值连接,上面不推荐的查询属于内连接;
  • 外连接:左外连接、右外连接、全外连接
    • 左外连接:字段 = 字段(+),“(+)”在等号右边表示左外连接
SELECT *
FROM emp e,dept d
WHERE e.deptno=d.deptno(+) ;
    • 右外连接:字段(+) = 字段,“(+)”在等号左边表示右外连接
SELECT *
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno ;

  

SQL:1999 语法支持

SELECT * | 字段 [别名]
FROM 表 [CROSS JOIN 表] [NATURAL JOIN 表] [JOIN] [USING(字段)] [ON(条件)]
[LEFT | RIGTH | FULL | OUTER JOIN 表] ;
  • 交叉连接,其主要的目的是为了产生笛卡尔积(不常用)
SELECT * | 字段 [别名] FROM 表 CROSS JOIN 表 ;
  • 自然连接,主要是消除掉笛卡尔积(内连接)(不常用)
SELECT * | 字段 [别名] FROM 表 NATURAL JOIN 表 ;
  • 使用 USING 子句,用户指定关联字段(不常用)
SELECT * | 字段 [别名] FROM 表 JOIN 表 USING(字段);
  • 使用 ON 子句指定关联条件(不常用)
SELECT * | 字段 [别名] FROM 表 JOIN 表 ON(条件);
  • 外连接(必须熟悉)
SELECT * | 字段 [别名] FROM 表 LEFT | RIGTH | FULL OUTER JOIN 表];
SELECT * FROM emp e LEFT OUTER JOIN dept d ON (e.deptno=d.deptno);
SELECT * FROM emp e RIGHT OUTER JOIN dept d ON (e.deptno=d.deptno);
SELECT * FROM emp e FULL OUTER JOIN dept d ON (e.deptno=d.deptno);

  

查询结果连接

SELECT [DISTINCT] * | 列名称 [别名] , 列名称 [别名] ,... FROM 数据表 [别名] , 数据表 [别名] ,...
[WHERE 条件(s)]
[ORDER BY 字段 [ASC | DESC] , 字段 [ASC | DESC] ,...]
[UNION | UNION ALL | INTERSECT | MINUS]
SELECT [DISTINCT] * | 列名称 [别名] , 列名称 [别名] ,... FROM 数据表 [别名] , 数据表 [别名] ,...
[WHERE 条件(s)]
[ORDER BY 字段 [ASC | DESC] , 字段 [ASC | DESC] ,...]
[UNION | UNION ALL | INTERSECT | MINUS]
SELECT [DISTINCT] * | 列名称 [别名] , 列名称 [别名] ,... FROM 数据表 [别名] , 数据表 [别名] ,...
[WHERE 条件(s)]
[ORDER BY 字段 [ASC | DESC] , 字段 [ASC | DESC] ,...]
  • UNION 操作,不显示重复记录
  • UNION ALL 操作,显示所有数据,包含重复数据
  • INTERSECT 操作,返回相同的部分,交集
  • MINUS 操作,返回不同的部分,是一个差集
 

组函数  

统计函数常见的有五个:COUNT()(个数)、SUM()(求和)、AVG()(平均)、MAX()(最大值)、MIN()(最 小值)。

 关于统计查询的限制:

  • 限制一:统计函数单独使用时(没有 GROUP BY 子句)只能够出现统计函数,不能够出现其它字段。

  • 限制二:使用统计查询时(存在 GROUP BY 子句),SELECT 子句之中只允许出现统计函数与分组字段, 其它的任何字段都不允许出现。

  • 限制三:统计函数在分组之中可以嵌套使用,但是嵌套之后的统计查询之中,SELECT 子句不允许再出现 任何的字段,包括分组字段。

关于 WHERE 和 HAVING 的区别? 

  • WHERE 子句:是在分组前使用,而且不能够使用统计函数进行验证,经过 WHERE 筛选后的数据才可以分组;
  • HAVING 子句:必须结合 GROUP BY 子句一起出现,是在分组后的过滤,可以使用统计函数。 

子查询

  • 在 WHERE 子句之中使用子查询
    • IN:在指定范围内
    • NOT IN:不在指定范围内
    • ANY
      • =ANY:此功能与 IN 操作完全一样
      • >ANY:比子查询的最小值要大
      • <ANY:比子查询的最大值要小
SELECT * FROM emp WHERE sal <ANY (
SELECT sal FROM emp WHERE job='MANAGER') 
    • ALL
      • >ALL:比子查询返回的最大值还要大
      • <ALL:比子查询最小值还要小
SELECT * FROM emp WHERE sal <ALL (
SELECT sal FROM emp WHERE job='MANAGER') 
  • 在 HAVING 子句之中使用子查询
SELECT deptno,AVG(sal) FROM emp
GROUP BY deptno HAVING AVG(sal)>(
SELECT AVG(sal) FROM emp)
  • 在 FROM 子句之中使用子查询
SELECT d.deptno,d.dname,d.loc,temp.count,temp.avg FROM dept d , (
SELECT deptno ,COUNT(empno) count,AVG(sal) avg FROM emp
GROUP BY deptno) temp
WHERE d.deptno=temp.deptno(+) ;

问题: FROM 子句查询和多表查询有什么差异?emp 表之中存在有 14000 条数据,dept 表中存在有 4000 条数据,查找这两张表会有什么差异呢?

  • 采用方式一的数据量,方式一使用的是多字段分组,那么就一定需要多表查询,多表查询一定会产生笛卡尔积;

            |- 积的数量:emp 的 14000 条 * dept 的 4000 条 = 56,000,000 条数据

  • 采用方式二的数据量,方式二使用的是子查询完成,需要分两步操作:

            |- 第一步(内嵌子查询):针对于 emp 表查询,最多操作 14000 条记录,最多返回 4000 条记录; |- 第二步,子查询和 dept 表关联;

            |- 积的数量:dept 表的 4000 条 * 子查询返回的最多 4000 条 = 16000000 条记录; |- 总的数据量:16000000 + 14000 = 16,014,000 条记录

      主要目的:子查询的出现主要是为了解决多表查询之中的性能问题

      次要目的:很多时候在 FROM 子句里面使用子查询,是因为在外部查询里无法再继续使用统计函数操作的时候

数据更新

复制表

CREATE TABLE myemp AS SELECT * FROM emp ;

数据删除

# 删除掉那些没有领导的雇员
DELETE FROM myemp WHERE mgr IS NULL ;
# 所有员工删除
DELETE FROM myemp;

  

猜你喜欢

转载自www.cnblogs.com/CSgarcia/p/11434295.html