数据库(Database,简称DB):存放数据的仓库
数据库管理系统(Database Management system,简称DBMS),比如Oracle,SQL,Server,DB2等
数据库管理员(Database Administrator,简称DBA),一种职业,专门从事数据库管理,维护等工作

SQL:(Structured Query Language,结构化查询语言。它是一种工业标准,专门用于跟各种关系型数据库进行交互,所有关系型数据库(比如Oracle,Access等)都遵循SQL标准,当然由于各种原因,各种关系型数据库产品并不是完全遵循SQL标准,它们在标准SQL的基础上有自己的独特扩展
SQL分为五个部分:
DDL:Data Definition Language,数据定义语言,创建删除或者修改各种数据对象的语法就属于该部分,比如创建或删除表
DCL:Data Control Language,数据控制语言,对数据的访问作一些控制,比如grant,revoke
DML:Data Manipulation Language,数据操作语言,对数据进行增删该操作,比如insert,delete,update
DQL:Data Query Language,数据查询语言,对数据进行检索操作,比如select
TCL:Transaction Control Language,事务控制语言,对事务进行控制操作,比如commit,rollback,savepoint

//较出名的数据库
大型:Oracle DB2 SQL Sever
中小型:MySQL
小型:Access
微型:SQLite

Oracle数据库使用步骤:
1.创建数据库。在安装时创建或者在装完后使用dbca命令创建
2.创建表空间
表空间(Table Space):存放数据表的空间。表空间是一个逻辑上的概念,物理上对应一个或者多个磁盘上的数据文件(Data File),数据库中的数据是存放在这些数据文件中
数据表(Table):存放数据的二维表格,逻辑上的概念。由行(Row)和列(Cloumn)构成,一行称为一条记录(Record),一列称为一个字段(Field)

startup --首先启动数据库实例,紧接着打开控制文件,然后打开数据文件
startup mount --只打开控制文件,而不打开数据文件
startup nomount --不打开控制文件(在控制文件丢失或出错时使用,这样可以重建控制文件)
shutdown immediate --在当前用户操作完毕后立即关闭数据库(最为推荐的方法)
shutdown abort --强行关闭数据库(会造成数据损坏)

net stop msdtc --停止ORACLE服务

–为表空间增加一个数据文件
alter tablespace dataspace add datafile ‘D:\data01.dbf’ size 100M;

–从表空间中删除数据文件
alter tablespace dataspace drop datafile ‘D:\data01.dbf’;

–报表命令
–设置ename字段名为 姓名 ,字段宽度为30
–col sal format 999,999,999 设置数字的显示格式
col ename heading ‘姓名’ format a30;
select ename from emp;

以sys用户登录
输入alter user scott account unlock;解锁scott用户,他的密码是tiger,输入后可以自己设定新密码。
alter user scott account lock;将用户scott锁住

让用户的密码到期
ALTER USER test PASSWORD expire ;

lsnrctl start开启虚拟机的数据库监听器
lsnrctl stop断开虚拟机的数据库监听器

sqlplus / nolog 进入SQL
conn /as sysdba //以sys身份登录
conn sys/123456 //以输入密码的形式登录
show user //显示当前登录的用户
startup //启动oracle数据库时令(不启动无法使用)
help +命令 //查找该命令作用
shutdown immediate 关闭Oracle数据库时令
quit/exit //都能完成退出SQL
Disconnect; //断开连接
Save c:\1.txt //把SQL存到文件
Ed c:\1.txt //编辑SQL语句
@ c:\1.txt //运行SQL语句
Desc emp; //描述Emp结构
select * from scott.emp; //在其他用户登录的情况下查询scott这个用户的表
/ //运行上一条语句

创建一个表空间
//1.
create tablespace mydb datafile ‘/home/oracle/mydb.dbf’ size 10m [autoextend on next 10m maxsize 100m];
//2.
create tablespace mydb
datafile ‘/home/oracle/mydb.dbf’
size 10m
autoextend on
next 10m
maxsize 100m;

clear scr; //清屏

删除表空间:drop tablespace mydb including contents and datafiles

3.创建用户
create user softeem identified by abc123 default tablespace mydb;//创建一个用户名为softeem的用户,密码为abc123,默认表空间为上面创建的mydb
默认表空间:该用户在创建表,视图,序列等数据对象时,如果没有显式指定用于存放的表空间,就存放在默认表空间中

删除用户:drop user softeem cascade(干净)
删除用户:drop user softeem(不干净)

4.给新用户授权
grant connect,resource to softeem
将连接数据库和对数据进行操作的权限授予给softeem用户
–让SCOTT这个用户拥有对staff的查询权限–且他不能授权给当前用户
grant select on staff to SCOTT;
–收回权限
revoke select on staff from SCOTT;
grant select,insert(sal) on staff to SCOTT;
–将所有权限赋给SCOTT这个用户
grant all privileges on staff to SCOTT;

connect,resource,dba等称为角色,是一组权限的集合
connect:连接权限
resource:对数据进行各种操作权限
dba:系统管理员权限

delete_catalog_role
execute_catalog_role
select_catalog_role
这三个角色用于访问数据字典视图和包

exp_full_database
imp_full_database
这两个角色用于数据的导入导出工具的使用

收回权限:revoke connect from softeem;

让用户拥有访问其他用户的权限
grant 权限(select\update\insert\delete) on schema.table to 用户
grant select on scott.emp to test;
grant all on scott.emp to test;–将表的所有相关权限付给test
grant update(ename) on emp to test;–可以控制到列(还有insert)

收回权限:revoke select on scott.emp from test;

查看权限:select * from user_sys_privs;

权限传递:Grant create session to test with admin option;
–可以就可以实现权限传递

–如果权限 sys->test->test1 ,这时断掉 test 的权限, test1 还会有权限

–角色:就是一堆权限的集合
Create role myrole;
Grant create table to myrole;
Drop role myrole;-- 删除角色

–创建示例:

–创建表空间
CREATE TABLESPACE baobao121
DATAFILE ‘/opt/oracle/oradata/baobaodata/baobao121.dbf’ SIZE 200M
AUTOEXTEND ON NEXT 50M
EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;

–创建临时表空间
create temporary tablespace baobao121_temp
tempfile ‘/opt/oracle/oradata/baobaodata/baobao121_temp.dbf’ size 50M
AUTOEXTEND ON NEXT 50M
EXTENT MANAGEMENT LOCAL;

–增加用户
create user baobao121 identified by baobao121
DEFAULT TABLESPACE baobao121
temporary tablespace baobao121_temp;

–增加权限
grant all privileges to baobao121;

–测试连接
conn baobao121/baobao121;
show user;
–显示应为 USER is “BAOBAO121”

–数据库设计范式----------------------------------
–第一范式:字段要设计的不可再分
Name 字段 可拆分成 FirstName+LastName
–第二范式: 两个表的关系,在第三张关系表中体现
比如学生和课程表。为多对多的关系。这种关系需要在第三张表中体现
–第三范式:多张表中,只存关系,不存具体信息(具体开发中用的最多)
比如: emp,dept
如果一对多用第三张表(关系表)来表示,则会出现问题。(一个员工可能属于多个部门,显然这是不符合现实逻辑的)

–总范式 数据库表关联越少越好, SQL 语句复杂度越低越好

Oracle数据类型
数据类型(datatype)是列(column)或存储过程中的一个属性。

Oracle支持的数据类型可以分为三个基本种类:字符数据类型、数字数据类型以及表示其它数据的数据类型。
字符数据类型----------------------------------------------------------
CHAR
大小写不敏感,固定长度,默认为1个字符长度,最多容纳2000个字符(字节),不足长度补空格
CHAR数据类型存储固定长度的子符值。一个CHAR数据类型可以包括1到2000个字符。如果对CHAR没有明确地说明长度,它的默认长度则设置为1.如果对某个CHAR类型变量赋值,其长度小于规定的长度,那么Oracle自动用空格填充。
VARCHAR2
可变长度,必须指定长度(范围:1-4000),实际赋值不能超过括号中指定最大长度,实际有多少个字符就占多少字节的空间,(Oracle推荐使用VARCHAR2)

存储可变长度的字符串。虽然也必须指定一个VARCHAR2数据变量的长度,但是这个长度是指对该变量赋值的的最大长度而非实际赋值长度。不需要用空格填充。最多可设置为4000个字符。因为VARCHAR2数据类型只存储为该列所赋的字符(不加空格),所以VARCHAR2需要的存储空间比CHAR数据类型要小。

NCHAR/NVARCHAR2

nchar 固定长度,用来表示国际编码字符,一个国际编码字符肯定不止占一个字节空间,例如,NCHAR(3)可以用来存放最多三个国际编码字符(不是三个字节),将”张三丰”赋给它没问题
nvarchar2 可变长度,用来表示变长的国际编码字符
NCHAR和NVARCHAR2数据类型分别存储固定长度与可变长度的字符数据,但是它们使用的是和数据库其他类型不同的字符集。在创建数据库时,需要指 定所使用的字符集,以便对数据库中数据进行编码。还可以指定一个辅助的字符集[即本地语言集(National Language Set,简称NLS)]。NCHAR和NVARCHAR2类型的列使用辅助字符集。在Oracle9i中,可以以字符而不是字节为单位来表示NCHAR和NVARCHAR2列的长度。

LONG
LONG数据类型可以存放2GB的字符数据,它是从早期版本中继承来的。现在如果想存储大容量的数据,Oracle推荐使用CLOB和NCLOB数据类型。在表和SQL语句中使用LONG类型有许多限制。
CLOB/NCLOB
CLOB和NCLOB数据类型可以存储多达4GB的字符数据。NCLOB数据类型可存储NLS数据。

数字数据类型--------------------------------------------------
Oracle使用标准、可变长度的内部格式来存储数字。这个内部格式精度可以高达38位。

NUMBER
数据类型可以有两个限定符,如:column NUMBER ( precision, scale)precision表示数字中的有效位。如果没有指定precision的话,Oracle将使用38作为精度。scale表示数字小数点右边的位数,scale默认设置为0.  如果把scale设成负数,Oracle将把该数字取舍到小数点左边的指定位数。
用来表示整数或者浮点数,语法形式NUMBER(precision,scale),precision表示数字中的有效位。如果没有指定precision的话,Oracle将使用38作为精度。scale表示数字小数点右边的位数,scale默认设置为0.  如果把scale设成负数,Oracle将把该数字取舍到小数点左边的指定位数。例如:
NUMBER(3) 表示最大可以存放三位十进制整数
NUMBER(5,2) 表示有效位总数为5,小数点右边有2位,也就是说整数有3位,比如123.35
NUMBER 可以存放38位十进制整数
日期数据类型
date
默认格式 DD-MM月-YY,可以使用TO_DATE函数将字符串转换成该类型
–将当前时间转化带三位小数的时间格式
TO_CHAR(SYSTIMESTAMP,‘YYYY-MM-DD HH24:MI:SS.FF3’)
Oracle标准日期格式为:DD-MON-YY HH:MI:SS。通过修改实例的参数NLS_DATE_FORMAT,可以改变实例中插入日期的格式。在一个会话期间,可以通过ALTER SESSION SQL命令来修改日期,或者通过使用SQL语句的TO_DATE表达式中的参数来更新一个特定值。

–Oracle数据库日期格式
SELECT TO_CHAR(SYSDATE, ‘YYYY-MM-DD HH24:MI:SS’) FROM DUAL;
SELECT TO_DATE(‘2016-9-29 14:59:23’, ‘YYYY-MM-DD HH24:MI:SS’) FROM DUAL;
–将数字转化为英文,结果为TWO HUNDRED TWENTY-TWO
SELECT TO_CHAR(TO_DATE(222, ‘J’), ‘JSP’) FROM DUAL;
–得出今天是周几
SELECT TO_CHAR(TO_DATE(‘2016-9-29’, ‘YYYY-MM-DD’), ‘DAY’) FROM DUAL;
–得出今天美国是周几
SELECT TO_CHAR(TO_DATE(‘2016-9-29’, ‘YYYY-MM-DD’), ‘DAY’, ‘NLS_DATE_LANGUAGE = American’) FROM DUAL;
–设置日期语言,与上句结果一样
ALTER SESSION SET NLS_DATE_LANGUAGE = ‘AMERICAN’;
–两个日期间的天数
SELECT FLOOR(SYSDATE - TO_DATE(‘20160926’, ‘YYYYMMDD’)) FROM DUAL;
–加载时间为null的用法
SELECT EMPNO, HIREDATE FROM EMP UNION SELECT 1, TO_DATE(NULL) FROM DUAL;
–按格式输出日期
SELECT TO_CHAR(TO_DATE(‘2016-09-29’, ‘YYYY-MM-DD’), ‘DAY’, ‘NLS_DATE_LANGUAGE = AMERICAN’) FROM DUAL;
–或者使用下面的语句修改日期格式的字符集类型
ALTER SYSTEM SET NLS_DATE_LANGUAGE = AMERICAN;
ALTER SESSION SET NLS_DATE_LANGUAGE = AMERICAN;
–查询数据库中格式类型有哪些
SELECT * FROM NLS_SESSION_PARAMETERS;
SELECT * FROM V$NLS_PARAMETERS;
–从数据中找到特定的数据,这个是找到小时数
SELECT EXTRACT(HOUR FROM TIMESTAMP ‘2016-9-29 15:30:23’) FROM DUAL;
–与上一句效果一样
SELECT SYSDATE, TO_CHAR(SYSDATE, ‘HH’), TO_CHAR(SYSDATE, ‘HH24’) FROM DUAL;
–判断两个时间之间相差的年月日
SELECT OLDER_DATE, NEWER_DATE, YEARS, MONTHS, ABS(TRUNC(NEWER_DATE - ADD_MONTHS(OLDER_DATE, YEARS12 + MONTHS))) DAYS
FROM
(
SELECT TRUNC(MONTHS_BETWEEN(NEWER_DATE, OLDER_DATE)/12) YEARS, MOD(TRUNC(MONTHS_BETWEEN(NEWER_DATE, OLDER_DATE)), 12) MONTHS, NEWER_DATE, OLDER_DATE FROM
( SELECT HIREDATE OLDER_DATE, ADD_MONTHS(HIREDATE, ROWNUM) + ROWNUM NEWER_DATE FROM EMP
)
)
–处理月份天数不定的方法
SELECT TO_CHAR(ADD_MONTHS(LAST_DAY(SYSDATE) + 1, -2), ‘YYYYMMDD’), LAST_DAY(SYSDATE) FROM DUAL;
–统计今年的年份
SELECT ADD_MONTHS(TRUNC(SYSDATE, ‘YEAR’), 12) - TRUNC(SYSDATE, ‘YEAR’) FROM DUAL;
–判断是否为闰年,就是判断2月是否为28天
SELECT CASE TO_CHAR(LAST_DAY(TO_DATE(&YEAR || ‘02’, ‘YYYYMM’)), ‘dd’) WHEN ‘28’ THEN ‘不是闰年’ ELSE ‘闰年’ END RU FROM DUAL;
SELECT CASE TO_CHAR(LAST_DAY(TO_DATE(‘2016’ || ‘02’, ‘YYYYMM’)), ‘dd’) WHEN ‘28’ THEN ‘NO’ ELSE ‘YES’ END RU FROM DUAL;
–显示不同时区的处理
SELECT TO_CHAR(NEW_TIME(SYSDATE, ‘GMT’, ‘EST’), ‘DD/MM/YYYY HH:MI:SS’), SYSDATE FROM DUAL;
–5秒钟一个间隔
SELECT TO_DATE(FLOOR(TO_CHAR(SYSDATE, ‘SSSSS’)/300) * 300, ‘SSSSS’), TO_CHAR(SYSDATE, ‘SSSSS’) FROM DUAL;
–一年的第几天
SELECT TO_CHAR(SYSDATE, ‘DDD’), SYSDATE FROM DUAL;
–计算时分秒毫秒
SELECT DAYS, A, TRUNC(A
24) HOURS, TRUNC(A2460 - 60TRUNC(A24)) Minutes,
TRUNC(A246060 - 60trunc(A2460)) Seconds, TRUNC(A246060100 - 100* TRUNC(A246060)) mSeconds
FROM
(SELECT TRUNC(SYSDATE) DAYS, SYSDATE - TRUNC(SYSDATE) A FROM DUAL)
–明天的时间
SELECT NEXT_DAY(SYSDATE, 6) FROM DUAL;
–日期 返回的是天 然后 转换为ss
select (sysdate-to_date(‘2016-9-1 12:55:45’,‘yyyy-mm-dd hh24:mi:ss’))
246060 from dual;
–round舍入到最接近的日期
select sysdate S1,
round(sysdate) S2,
round(sysdate,‘year’) YEAR,
round(sysdate,‘month’) MONTH,
round(sysdate,‘day’) DAY from dual
–trunc[截断到最接近的日期,单位为天] ,返回的是日期类型
select sysdate S1,
trunc(sysdate) S2, --返回当前日期,无时分秒
trunc(sysdate,‘year’) YEAR, --返回当前年的1月1日,无时分秒
trunc(sysdate,‘month’) MONTH, --返回当前月的1日,无时分秒
trunc(sysdate,‘day’) DAY --返回当前星期的星期天,无时分秒
from dual
–返回日期列表中最晚日期
select greatest(‘01-1月-04’,‘04-1月-04’,‘10-2月-04’) from dual
–计算时间差
–注:oracle时间差是以天数为单位,所以换算成年月,日
select floor(to_number(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))/365) as spanYears from dual; --时间差-年
select FLOOR(TO_NUMBER(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))) as spanMonths from dual; --时间差-月
select floor(to_number(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))) as spanDays from dual; --时间差-天
select floor(to_number(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))24) as spanHours from dual; --时间差-时
select floor(to_number(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))
2460) as spanMinutes from dual; --时间差-分
select floor(to_number(sysdate-to_date(‘2007-11-02 15:55:03’,‘yyyy-mm-dd hh24:mi:ss’))246060) as spanSeconds from dual; --时间差-秒
–查找月的第一天,最后一天
SELECT Trunc(Trunc(SYSDATE, ‘MONTH’) - 1, ‘MONTH’) First_Day_Last_Month,
Trunc(SYSDATE, ‘MONTH’) - 1 / 86400 Last_Day_Last_Month,
Trunc(SYSDATE, ‘MONTH’) First_Day_Cur_Month,
LAST_DAY(Trunc(SYSDATE, ‘MONTH’)) + 1 - 1 / 86400 Last_Day_Cur_Month
FROM dual;
–查询一年12个月的信息
Select to_char(add_months(trunc(sysdate,‘year’),Rownum - 1),‘yyyy-mm’)
From dual Connect By Rownum <= 12;
–查询每月30天的信息
Select to_char(trunc(sysdate,‘month’) + Rownum - 1,‘yyyy-mm-dd’)
From dual Connect By Rownum <= extract(Day From last_day(trunc(Sysdate,‘month’)));
–目前时间日期信息
SELECT EXTRACT(YEAR FROM SYSDATE) FROM DUAL;–return Current Year
SELECT EXTRACT(MONTH FROM SYSDATE) FROM DUAL;–return Current Month
SELECT EXTRACT(DAY FROM SYSDATE) FROM DUAL;–return Current Day

其它的数据类型-------------------------------------------------
RAW/LONG
RAW数据类型主要用于对数据库进行解释。指定这两种类型时,Oracle以位的形式来存储数据。RAW数据类型一般用于存储有特定格式的对象,如位图。 RAW数据类型可占用2KB的空间,而LONG RAW数据类型则可以占用2GB大小。
ROWID
ROWID是一种特殊的列类型,称之为伪列(pseudocolumn)。ROWID伪列在SQL SELECT语句中可以像普通列那样被访问。Oracle数据库中每行都有一个伪列。ROWID表示行的地址,ROWID伪列用ROWID数据类型定义。ROWID与磁盘驱动的特定位置有关,因此,ROWID是获得行的最快方法。但是,行的ROWID会随着卸载和重载数据库而发生变化,因此建议不要在事务 中使用ROWID伪列的值。例如,一旦当前应用已经使用完记录,就没有理由保存行的ROWID.不能通过任何SQL语句来设置标准的ROWID伪列的值。列或变量可以定义成ROWID数据类型,但是Oracle不能保证该列或变量的值是一个有效的ROWID.

LOB
LOB(大型对象)数据类型,可以保存4GB的信息。LOB有以下3种类型:
CLOB,只能存储字符数据。
NCLOB,保存本地语言字符集数据。
BLOB,以二进制信息保存数据。
可以指定将一个LOB数据保存在Oracle数据库内,还是指向一个包含次数据的外部文件。LOB可以参与事务。管理LOB中的数据必须通过DBMS_LOB PL/SQL内置软件包或者OCI接口。为了便于将LONG数据类型转换成LOB,Oracle9i包含许多同时支持LOB和LONG的函数,还包括一个ALTER TABLE语句的的新选择,它允许将LONG数据类型自动转换成LOB.
BFILE
BFILE数据类型用做指向存储在Oracle数据库以外的文件的指针。
XMLType
作为对XML支持的一部分,Oracle9i包含了一个新的数据类型XMLType.定义为XMLType的列将存储一个在字符LOB列中的XML文档。有许多内置的功能可以使你从文当中抽取单个节点,还可以在XMLType文档中对任何节点创建索引。

用户自定义数据------------------------------------------------
从Oracle8以后,用户可以定义自己的复杂数据类型,它们由Oracle基本数据类型组合而成。
AnyType/AnyData/AnyDataSet
Oracle包括3个新的数据类型,用于定义在现有数据类型之外的数据结构。其中每种数据类型必须用程序单元来定义,以便让Oracle9i知道如何处理这些类型的特定实现。

类型转换------------------------------------------------------
Oracle会自动将某些数据类型转换成其他的数据类型,转换取决于包括该值的SQL语句。
数据转换还可以通过Oracle的类型转换函数显示地进行。
连接与比较,在大多数平台上Oracle SQL中的连接操作符用两条竖线(||)表示。连接是将两个字符值连接。Oracle的自动类型转换功能使得两个数字值也可以进行连接。
NULL
NULL值是关系数据库的重要特征之一。实际上,NULL不代表任何值,它表示没有值。如果要创建表的一个列,而这个列必须有值,那么应将它指定为NOT NULL,这表示该列不能包含NULL值。任何数据类型都可以赋予NULL值。NULL值引入了SQL运算的三态逻辑。如果比较的一方是NULL值,那么会出现3种状态:TURE、FALSE以及两者都不是。因为NULL值不等于0或其他任何值,所以测试某个数据是否为NULL值只能通过关系运算符IS NULL来进行。NULL值特别适合以下情况:当一个列还未赋值时。如果选择不使用NULL值,那么必须对行的所有列都要赋值。这实际上也取消了某列不需要值的可能性,同时对它赋的值也很容易产生误解。这种情况则可能误导终端用户,并且导致累计操作的错误结果。

注释
–这是单行注释

/*
这是多行注释
*/

–创建------------------------------------------------------------------
–创建表
CREATE TABLE STUDENT
(
SNO NUMBER(6),
SNAME VARCHAR2(20),
BIRTH DATE,
PHONE CHAR(11),
SIGHT NUMBER(2, 1)
);

–首先建立一张只包含 20 部门员工信息的表:
CREATE TABLE emp20 AS SELECT * FROM emp WHERE deptno=20 ;

–重命名表
Rename student to student1;

–清空表中数据
Truncate table student;
DELETE FROM student;
–正常情况下删除数据,如果发现删除错了,则可以通过 rollback 回滚。如果使用了截断表,则表示所有的数据不可恢复了.所以速度很快
–删除表
Drop table student;

–update 语句
–将编号为 7779 用户的工作换成编号为 7566 的雇员的工作和所属上级。
–如果子查询中返回的是空,则目标字段也更新成 NULL.
UPDATE myemp SET(job,mgr) = (SELECT job,mgr FROM myemp WHERE empno=7566) WHERE empno=7779 ;

–数据录入
INSERT INTO STUDENT VALUES(1001,‘刘玄德’,‘23-3月-1989’,‘13415974126’,5.2);
INSERT INTO STUDENT(SNO, SNAME) VALUES(1002, ‘张飞’);

–查询------------------------------------------------------------------
SELECT * FROM STUDENT;–查询表内容
select * from tab;–查看当前用户所有表
select * from tab where substr(tname,0,4)!=‘BIN′;−−产看当前用户非临时表select∗fromtabwheretnamenotlike′BIN'; --产看当前用户非临时表 select * from tab where tname not like 'BIN′;−−产看当前用户非临时表select∗fromtabwheretnamenotlike′BIN%’;–模糊查询,不显示名字前几项是BIN$的表
–嵌套语句查询选修课程编号为‘C2’的学员姓名和所属单位
select sname,sdw from s where sno in (select sno from sc where cno=‘c1’);
–查询选修全部课程的学员姓名和所属单位。
select sname,sdw from s where not exists (select * from c where not exists (select * from sc where sc.sno=s.sno and sc.cno=c.cno));
–选修课超过5门的学员学号和所属单位
select sno,sdw from s where sno in (select sno from sc group by sno having count(*) > 5);

–SCOTT用户-------------------------------------------------------------------
–查出奖金大于工资的员工信息
select * from emp where comm>sal;
–找出每个员工奖金和工资的总和
select sal+comm,ename from emp;
–找出部门 10 中的经理(MANAGER)和部门 20 中的普通员工(CLERK)
select * from emp where ((deptno=10 and job=‘mananger’)or(deptno=20 and job=‘clerk’));
–找出部门 10 中既不是经理也不是普通员工,而且工资大于等于 2000 的员工
select * from emp where deptno=10 and (job not in(‘mananger’,‘clerk’)and sal>2000);
–找出有奖金的员工的不同工作
select distinct job from emp where comm is not null and comm>0;
–找出没有奖金或者奖金低于 500 的员工
select * from emp where ((comm is null) or (comm<500));
–显示雇员姓名,根据其服务年限,将最老的雇员排在最前面
select ename,hiredate from emp order by hiredate;

–多表查询--------------------------------------------------------------
–笛卡尔集
–显示学生与课程的集合,所有的可能
select * from student, course;
–显示学号为1001,课程为20001的信息
select * from student, course where sno=1001 and cno=20001;
–显示学生的成绩信息
select st.*, score from student st, sc where st.sno=sc.sno;
–显示学号为1001的学生平均成绩
select avg(score) from course,sc where sno=1001 and course.cno=sc.cno;
select decode(sex,‘0’,‘男’,‘1’,‘女’) as 性别,round(avg(score)) from student,sc,course where cname=‘C程序设计’ and sc.cno=course.cno and student.sno=sc.sno group by sex;
– 多级排序,性别,年龄,视力
select * from student order by sex desc,birth desc, sight;

–列别名可以用as,也可以不用;表别名不能用as。如果别名中含有特殊符号号(除英文字母和汉字,比如+字符),用""引起来
–Oracle中字符串用单引号括起来
select sc.sno as 学号,sname as 姓名,avg(score) as “C++平均成绩” from student st,sc where st.sno=sc.sno group by sc.sno,sname;
–显示学生课程为20001的信息
select st.sno as 学号,sname as 姓名,score as C语言 from student st,sc where st.sno=sc.sno and cno=20001 order by score desc;
–显示挂科的人的信息,如果有人挂了两科也只会显示一次
select distinct st.sno,st.sname from student st,course,sc where st.sno=sc.sno and course.cno=sc.cno and sc.score < 60;

–连接操作,通过连接操作实现多表查询-----------------------------------------------------------------------
SQL-92标准所定义的FROM子句的连接语法格式为:
FROM join_table join_type join_table [ON (join_condition)]
join_type左边的表称为左表,右边的表称为右表
其中join_table指出参与连接操作的表名,连接可以对同一个表操作,也可以对多表操作,对同一个表操作的连接又称做自连接。
join_type 指出连接类型,可分为三种:内连接、外连接和交叉连接。
内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行。根据所使用的比较方式不同,内连接又分为等值连接、自然连接和不等连接三种。
外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN)、右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接(FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是,外连接不只列出与连接条件相匹配的行,而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。
LEFT JOIN = LEFT OUTER JOIN
RIGHT JOIN = RIGHT OUTER JOIN
FULL JOIN = FULL OUTER JOIN
交叉连接(CROSS JOIN)没有WHERE 子句,它返回连接表中所有数据行的笛卡尔积,其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
连接操作中的ON (join_condition) 子句指出连接条件,它由被连接表中的列和比较运算符、逻辑运算符等构成。

外连接分为左外连接(也称左连接),右外连接(也称右连接)和全外连接(也称全连接)三种
匹配的记录(即满足连接条件的记录)都保留,不匹配的记录的处理根据外连接类型不同而不同
对于左外连接,左表中的不匹配的记录保留,右表中的不保留,右表中的相应字段为NULL
右外连接跟左外连接相反,全外连接就是他们二者的并集

/*
1 2
2 4
3 6
4
5

内连接
2 2
4 4

满连接
1
2 2
3
4 4
5
6

左连接
1
2 2
3
4 4
5

右连接
2 2
4 4
6
*/

–自连接
select c1., c2. from course c1, course c2;
–交叉连接,即笛卡尔积,就是不使用where子句
select * from student, course;

–内连接根据所使用的比较方式不同,分为等值连接,不等连接和自然连接三种
– 等值连接,inner可以省略
select * from student inner join sc on student.sno=sc.sno;
– select * from student join sc on student.sno=sc.sno; – 和上面的等效
– select * from student,sc where student.sno=sc.sno; --和上面的等效
select empno, ename, sal, emp.deptno, dname from emp, dept where emp.deptno = dept.deptno;

– 不等连接
select * from student inner join sc on student.sno<sc.sno;
select ename,empno,grade from emp,salgrade where sal between losal and hisal;
– 自然连接,就是将重复的列去掉
select student.*,sc.cno,sc.score from student inner join sc on student.sno=sc.sno;
select e.empno,e.ename,m.empno,m.ename from emp e,emp m where e.mgr = m.empno;
select e.empno,e.ename,m.empno,m.ename from emp e,emp m where m.mgr = e.empno;

–左(外)连接
select st.sno,st.sname,sc.cno,sc.score
from student st left outer join sc on st.sno=sc.sno;
– from student st left join sc on st.sno=sc.sno; – 和上面的等效
– where cno is not null;
–左外联接(Left Outer Join )
select empno,ename,dname from emp left outer join dept on emp.deptno = dept.deptno;

–右(外)连接
select st.sno,st.sname,sc.cno,sc.score
from student st right outer join sc on st.sno=sc.sno;
– from student st right join sc on st.sno=sc.sno; – 和上面的等效
–右外联接(Right Outer Join)
select empno,ename,dname from emp right outer join dept on emp.deptno = dept.deptno;

–全(外)连接
select st.sno,st.sname,sc.cno,sc.score
from student st full outer join sc on st.sno=sc.sno;
– from student st full join sc on st.sno=sc.sno; – 和上面的等效
–满外联接(Full Outer Join)
select empno,ename,dname from emp full outer join dept on emp.deptno = dept.deptno;

–全(外)连接就是左连接和右连接结果集的并集
select st.sno,st.sname,sc.cno,sc.score from student st left outer join sc on st.sno=sc.sno
union
select st.sno,st.sname,sc.cno,sc.score from student st right outer join sc on st.sno=sc.sno;

–子查询(嵌套查询):在select语句中还有select语句
select * from (select sno,sname,sight from student order by sight desc) where rownum<4;
select student.* from student,sc where student.sno=sc.sno and sc.cno=20001 and sc.score < (select avg(score) from sc where cno=20001);
select student.,sc.score from student,sc where student.sno=sc.sno and sc.cno=20001 and 80<(select avg(score) from sc where cno=20001);
– exists关键字用于判断后面的集合是否为空集,如果为空集,条件不满足,否则满足,not exists相反
select student.
,sc.score from student,sc where student.sno=sc.sno and sc.cno=20001 and exists (select * from sc where cno=20001 and score>91);

–UNION
–并集,所有的内容都查询,重复的只显示一次,使用此语句重复的内容不再显示了
SELECT * FROM emp UNION SELECT * FROM emp20 ;
–UNION ALL
–并集,所有的内容都显示,包括重复的,重复的内容依然显示
SELECT * FROM emp UNION ALL SELECT * FROM emp20 ;
select * from emp1 e where (select count(*) from (select id from emp1 union all select id from sext) t where t.id = e.id) < 2;

–INTERSECT
–交集,只显示重复的,只显示了两个表中彼此重复的记录。
SELECT * FROM emp INTERSECT SELECT * FROM emp20 ;

–MINUS
–差集,只显示对方没有的(跟顺序是有关系的)。返回差异的记录,只显示了两张表中的不同记录
SELECT * FROM emp minus SELECT * FROM emp20 ;

–分页查询
–将emp表按sal倒叙排好后显示前5行,并在他前面再加一列序号,然后显示出序号大于等于3的所有列
select * from ( select rownum no,e.* from ( select * from emp order by sal desc ) e where rownum<=5 ) where no>=3;
–与上一条语句效果一样
select * from ( select rownum no,e.* from ( select * from emp order by sal desc ) e ) where no>=3 and no<=5;
–为查出来的数据标号,以便后来的分页处理
select tasks.*,
trunc(cindex/4) as cpage,
trunc((cindex-trunc(cindex/4)*4)/2) as ccol
from
(
select empno,
ename,
–以job分类,然后按照empno来排序编号
(row_number() over(partition by job order by empno)-1) as cindex
from
emp
)tasks
order by tasks.empno,tasks.cindex;

-SQL的单记录函数

–关键字-------------------------------------------
DELETE
–将学号为1003的这条学生的信息删除
delete from student where sno=1003;
UPDATE
–将学号为1001的学生名字改为张三丰
update student set sname=’张三丰’ where sno=1001;

||–字符串连接符
–从student中打印学生的姓名信息,在名字之前加上学生两个字
select ‘学生’ || sname from student;

between
–打印student中学号介于1002到1004的学生的所有数据
select * from student where sno>=1002 and sno<=1004;
select * from student where sno between 1002 and 1004;
select * from student where sno not between 1002 and 1004;

不等于
<>
!=

DISTINCT
select sex from student;只显示学生的性别信息(显示重复的)
select distinct sex from student;显示学生的性别信息(不显示重复的)

LIKE
模糊查询
通配符:
%:匹配零个或者多个任意字符
_ :匹配一个任意字符
select * from student where sname like ‘张%’;结果会显示所有有张的信息,有张三,张三丰
select * from student where sname like ‘张_’;结果只会显示张三
select * from student where sname like ‘张_ ';结果只会显示张三丰
select * from student where sname like ‘%四%’;结果会显示所有名字里面带有四的信息
select * from emp where ename like '%*
%’ escape '’;-- _表示一个字符,escape表示后面的那个符号不当成特殊字符处理

NULL
判断某个字段是否为NULL,应该使用is (not) null,不能使用(!)=null
Oracle关键字大小写不敏感,NULL和null一样

–处理空值排序
–按照comm降序排序
–nulls last(first)等同于nulls last or nulls first
–意思就是空值显示在后面
select * from emp order by comm desc nulls last;
–空值显示在前面
select * from emp order by comm desc nulls first;

SELECT * FROM PDM_DOCID WHERE 1 = 0;–主要用于读取表的结构而不考虑表中的数据,这样节省了内存,可以不用保存结果集。是为FALSE的语句
SELECT * FROM PDM_DOCID WHERE 1 = 1;–没毛用,若是正确则等同于SELECT * FROM PDM_DOCID

SYSDATE–当前系统日期时间
select sysdate from dual;

伪列:跟真实的列不一样,他不占据数据库存储空间,但是可以通过任何表或者视图去访问它(只能查询),一般是通过计算得到的,常见的有rowid,rownum,sysdate等
rowid:相当于行地址,用来唯一的标识一行,不同的行的rowid不一样,通过rowid可以快速访问指定行,
rownum:查询结果集中行的编号,从1开始
sysdate:系统当前日期时间

例如:
SQL>select rowid,rownum,sname from student;

ROWID ROWNUM SNAME


AAAMiaAAFAAAAAUAAA 1 张三
AAAMiaAAFAAAAAUAAB 2 李四
AAAMiaAAFAAAAAUAAC 3 王五
AAAMiaAAFAAAAAUAAD 4 赵六
AAAMiaAAFAAAAAUAAE 5 田七
AAAMiaAAFAAAAAUAAF 6 王八
AAAMiaAAFAAAAAUAAG 7 刘九

–TopN 查询
–rownum只能用于<,如果要用>要么用rownumber()OVER,要么就实例化
–rownum是对结果集的编序排列,始终是从1开始
select * from emp where rownum=1 or rownum=2;
–将它按sal倒叙排好后输出前5行
select * from (select * from emp order by sal desc) where rownum <= 5;
–显示表中的前5行,然后再将这5行按照sal倒叙排好后输出
select * from emp where rownum<=5 order by sal desc;

–ROW_NUMBER() OVER()解决
SELECT empno,ename,job,mgr,hiredate FROM (SELECT empno,ename,job,mgr,hiredate,ROW_NUMBER() OVER(ORDER BY empno) rk FROM emp) t WHERE rk > 2;

–多行子查询
–any就是大于其中任意一个都可以
select * from emp where sal > any(select avg(sal) from emp group by deptno);
–some类似于any,表示大于其中的任意一个
select * from emp where sal > some(select sal from emp where job=‘MANAGER’);
–all表示要大于里面的所有的才可以
select * from emp where sal > all(select avg(sal) from emp group by deptno);
–in
select * from emp where job in (select job from emp where ename = ‘MARTIN’ or ename = ‘SMITH’);

–exists
–exists用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False
select * from emp where exists ( select sal from emp20 where emp.deptno = emp20.deptno );
–与上一句效果一样
–exists先执行外部内容,in先执行子查询部分
select * from emp where sal in ( select sal from emp20 where emp.deptno = emp20.deptno );

–in不会对null进行处理
select 1 from dual where null in (0,1,2,null);

select * from emp1 e where not exists(select * from sext s where e.id = s.id);
select * from emp1 where id not in (select emp1.id from emp1,sext where emp1.id = sext.id);
select * from emp1 where id not in (select id from emp1 intersect select id from sext);

–dbms_random.value()产生随机数。这条语句是随机返回5条记录
Select * from (select ename,job from emp order by dbms_random.value()) where rownum<=5;

–<>all表示不等于所有的
select * from emp1 e where e.id <> all(select id from sext);

–merge 语句
create table test1(eid number(10), name varchar2(20),birth date,salary number(8,2));
insert into test1 values (1001, ‘张三’,to_date(‘19700520’,‘yyyymmdd’), 2300);
insert into test1 values (1002, ‘李四’,to_date(‘19730416’,‘yyyymmdd’), 6600);
create table test2(eid number(10), name varchar2(20),birth date,salary number(8,2));
–更新表中数据
merge into test2 using test1 on (test1.eid = test2.eid )
when matched
then update set name = test1.name, birth = test1.birth, salary = test1.salary
when not matched then
insert (eid, name, birth, salary) values(test1.eid, test1.name, test1.birth, test1.salary);
select * from test2;

ALTER
–改变表的名字(将名为student的表改名为dj)
alter talbe dj rename to student;
–删除名为student表中的名为sex的那一行
alter table student drop column sex;
–在表的末尾添加一个名为sex的行
alter table student add sex char(1);
–将sno的大小调整为number(8)
alter table student modify sno number(8);
–改字段的名称
alter table table2 rename column result to result2;
–删除字段
Alter table student drop column age;

Desc
desc student 显示表的内容

rollback
–恢复成上次更改之前的数据状态

–函数-------------------------------------------------------------------------
/*
dual是一张只有一个字段,一行记录的表.他不存储主题数据.
他的存在,是为了操作上的方便.因为select 都是要有特定对象的.
不一定要dual ,也可以这样
create table mydual( dummy varchar2(1));
也可以实现和dual 同样的效果:
select 999*999 from mydual;
*/

–nvl();将空的数据转化为0
select nvl(comm,0) from emp;
–使用nvl()函数强制分组函数处理空值
select avg(nvl(comm,0)) from emp;
select sal+nvl(comm,0),ename from emp;–nvl会将空的数据转换为0
select sal+comm,ename from emp;–这个表中有些成员的comm值为空,导致sal+comm的值也变为空了

–nvl2(expr1,expr2,expr3)
–如果参数表达式expr1值为NULL,则NVL2()函数返回参数表达式expr3的值;如果参数表达式expr1值不为NULL,则NVL2()函数返回参数表达式expr2的值。
–total 就是nvl2(comm,sal+comm,sal)的一个别名
select empno,ename,sal,comm,nvl2(comm,sal+comm,sal) total from emp;

–nullif(expression1 , expression2 )
/*
如果两个表达式不相等,nullif返回第一个 expression1 的值。
如果两个表达式相等,nullif返回空值NULL。
*/
select NULLIF(‘222’,’’) from dual;
select nullif(‘222’,‘222’) from dual;

–coalesce(expression_1, expression_2, …,expression_n)
–依次考察各参数表达式,遇到非 null 值即停止并返回该值。
select empno,ename,sal,comm,coalesce(sal+comm,sal,0)总收入 from emp;

–CASE 表达式
–end是这一字段的名称
select empno,ename,sal ,
case deptno
when 10 then ‘财务部’
when 20 then ‘研发部’
when 30 then ‘销售部’
else ‘未知部门’
end 部门
from emp;

–DECODE()函数
–和 case 表达式类似,decode()函数也用于实现多路分支结构
select empno, ename, sal ,
decode(deptno,
10,‘财务部’,
20,‘研发部’,
30,‘销售部’,
‘未知部门’)
部门
from emp;

–单行函数嵌套
–左侧填充,将第一个字母变为大写,过滤首尾空格
select empno, lpad(initcap(trim(ename)),10,’ ') name, job, sal from emp;

–ASCII:返回与指定的字符对应的十进制数
select ascii(‘A’) A,ascii(‘a’) a,ascii(‘0’) zero,ascii(’ ') space from dual;

–CHR:返回对应的字符, 给出整数
select chr(54740) zhao,chr(65) chr65 from dual;

–CONCAT:连接两个字符串
select concat(‘010-’,‘88888888’) || ‘转 23’ 高乾竞电话 from dual;
select concat(‘a’,‘b’) from dual;
–效果与上句话一样,但是标题改变为’a’||‘b’
Select ‘a’ || ‘b’ from dual;

–INITCAP:返回字符串并将字符串的第一个字母变为大写
select initcap(‘Smitch’) upp from dual;
select initcap(ename) from emp;

–INSTR(C1,C2,I,J):在一个字符串中搜索指定的字符,返回发现指定的字符的位置
–C1 被搜索的字符串 C1
–C2 希望搜索的字符串 C2
–I 搜索的开始位置,默认为1
–J 出现的位置,默认为1
/*
instr( string1, string2, start_position,nth_appearance )
返回值为查找的位置
string1 源字符串
string2 要在string1中查找的字符串
start_position 代表string1 的哪个位置开始查找。如果省略默认为1.字符串索引从1开始。如果此参数为正,从左到右开始检索,如果此参数为负,从右到左检索,返回要查找的字符串在源字符串中的开始索引。
nth_appearance 代表要查找第几次出现的string2. 如果省略,默认为 1.如果为负数系统会报错。
*/
select instr(‘oracle traning’,‘ra’,1,2) instring from dual;
Select instr(‘Hello World’,‘or’) from dual;–8 indexof

–位置索引号从1开始。如果String2在String1中没有找到,instr函数返回0。
SELECT instr(‘syranmo’,‘s’) FROM dual; – 返回 1
SELECT instr(‘syranmo’,‘ra’) FROM dual; – 返回 3
SELECT instr(‘syran mo’,‘a’,1,2) FROM dual; – 返回 0

–LENGTH:返回字符串的长度
select ename,length(ename),mgr,length(mgr),sal,length(sal),length(to_char(sal)) from scott.emp;
Select length(ename) from emp;

–LOWER:返回字符串,并将所有的字符小写
select lower(‘AaBbCcDd’) clower from dual;

–UPPER:返回字符串,并将所有的字符大写
select upper(‘AaBbCcDd’) cupper from dual;
select upper(‘aBcde’) from dual;
select * from emp where ename = upper(‘smith’);

–RPAD 和 LPAD : 粘贴字符
–RPAD 在列的右边粘贴字符
–LPAD在列的左边粘贴字符
select lpad(rpad(‘gao’,10,’’),17,’’) from dual;
–Lpad
/*
左侧填充
lpad( string, padded_length, [ pad_string ] )
string 准备被填充的字符串;
padded_length 填充之后的字符串长度,也就是该函数返回的字符串长度,如果这个数量比原字符串的长度要短,lpad函数将会把字符串截取成从左到右的n个字符;
pad_string 填充字符串,是个可选参数,这个字符串是要粘贴到string的左边,如果这个参数未写,lpad函数将会在string的左边粘贴空格

/
select lpad(‘Smith’,10,’
’) from dual;
–Rpad
–右侧填充
select rpad(‘Smith’,10,’*’) from dual;

–LTRIM 和 RTRIM
–LTRIM 删除左边出现的字符串
–RTRIM 删除右边出现的字符串
select ltrim(rtrim(‘gaoyi*’,’’),’’) from dual;

–SUBSTR(string,start,count)
–返回指定的字符串,第二个参数表示从什么地方开始,第三个参数表示长度
select substr(‘13088888888’,3,4) from dual;
Select substr(‘abcde’,length(‘abcde’)-2) from dual;
select substr(‘abcde’,3) from dual;–与上句等效
–负数表示从后向前数几位
Select substr(‘abcde’,-2,3) from dual;
–(-3)表示从右向左第三个字符开始向后截取,(3)表示截取三个字符
select substr(‘abcde’,-3,3) from dual;
–过头了,就不管了
select substr(‘abcde’,-9,100) from dual;
select substr(‘abcde’,0,100) from dual;
–0表示从左边第一个字符开始截取,小于0的都表示不截取
select substr(‘abcdefg’,0,-3) from dual;

–REPLACE(‘string’,‘s1’,‘s2’)
–表示用第三个参数字符串替代第一个参数字符串中的第二个参数字符串,第三个参数可以省略,默认为""
–string 是希望被替换的字符或变量
–s1 被替换的字符串
–s2 要替换的字符串
select replace(‘he love you’,‘he’,‘I’) from dual;
Select replace(ename,‘a’,‘A’) from emp;

–SOUNDEX:返回一个与给定的字符串读音相同的字符串
create table table1(xm varchar(8));
insert into table1 values(‘weather’);
insert into table1 values(‘wether’);
insert into table1 values(‘wao’);
select xm from table1 where soundex(xm)=soundex(‘weather’);

–TRIM(‘s’ from ‘string’)
–过滤首尾空格
–LEADING 剪掉前面的字符
–TRAILING 剪掉后面的字符
–如果不指定,默认为空格符
select trim(’ Mr Smith ') from dual;

–ABS: 返回指定值得绝对值
select abs(100),abs(-100) from dual;

–ACOS:返回反余弦的值
select acos(-1) from dual;

–ASIN:返回反正弦的值
select asin(0.5) from dual;

–ATAN:返回一个数字的反正切值
select atan(1) from dual;

–CEIL:返回大于或等于给出数字的最小整数
select ceil(3.1415927) from dual;

–COS:返回一个给定数字的余弦
select cos(-3.1415927) from dual;

–COSH:返回一个数字的反余弦值
select cosh(20) from dual;

–EXP:返回一个数字 e 的 n 次方根
select exp(2),exp(1) from dual;

–FLOOR:返回对给定数字取整数
select floor(2345.67) from dual;

–LN:返回一个数字的对数值
select ln(1),ln(2.7182818) from dual;

–LOG(n1,n2)
–返回一个以n1为底n2 的对数
select log(2,1),log(2,4) from dual;

–MOD(n1,n2):取余
–返回一个n1除以n2 的余数
select mod(10,3),mod(3,3),mod(2,3) from dual;
select mod(7,2) from dual;
–查询跳过表中的偶数行
–row_number()从1开始,为每一条分组记录返回一个数字,这里的ROW_NUMBER() OVER (ORDER BY ename) 是先把ename列排序,再为排序以后的每条ename记录返回一个序号。
select ename from (select row_number() over (order by ename) rn,ename from emp) x where mod(rn,2)=1;

–POWER:返回n1的n2 次方根
select power(2,10),power(3,3) from dual;

–ROUND 和 TRUNC :按照指定的精度进行舍入
select round(55.5),round(-55.4),trunc(55.5),trunc(-55.5) from dual;
/*
round(number,digits)
number,要四舍五入的数,digits是要小数点后保留的位数
num_digits 大于 0,则四舍五入到指定的小数位。
num_digits 等于 0,则四舍五入到最接近的整数。
num_digits 小于 0,则在小数点左侧进行四舍五入。
num_digits 省略,等同于num_digits 等于 0。
*/
select round(412,-2) from dual;
select round(412.313,2) from dual;

–Trunc
–与round类似,结尾取整的数字
select trunc(412.13,2) from dual;

–SIGN:取数字n的符号,大于0 返回1 ,小于0 返回-1 ,等于0 返回0
select sign(123),sign(-100),sign(0) from dual;

–SIN:返回一个数字的正弦值
select sin(1.57079) from dual;

–SIGH:返回双曲正弦的值
select sin(20),sinh(20) from dual;

–SQRT:返回数字n 的根
select sqrt(64),sqrt(10) from dual;

–TAN:返回数字的正切值
select tan(20),tan(10) from dual;

–TANH:返回数字n 的双曲正切值
select tanh(20),tan(20) from dual;

–TRUNC:按照指定的精度截取一个数
select trunc(124.166,-2) trunc1,trunc(124.1666,2) from dual;

–ADD_MONTHS:增加或减去月份
select to_char(add_months(to_date(‘199912’,‘yyyymm’),2),‘yyyymm’) from dual;
select to_char(add_months(to_date(‘199912’,‘yyyymm’),-2),‘yyyymm’) from dual;
select sysdate,add_months(sysdate,12) from dual; --加1年
select sysdate,add_months(sysdate,1) from dual; --加1月
select sysdate,to_char(sysdate+7,‘yyyy-mm-dd HH24:MI:SS’) from dual; --加1星期
select sysdate,to_char(sysdate+1,‘yyyy-mm-dd HH24:MI:SS’) from dual; --加1天
select sysdate,to_char(sysdate+1/24,‘yyyy-mm-dd HH24:MI:SS’) from dual; --加1小时
select sysdate,to_char(sysdate+1/24/60,‘yyyy-mm-dd HH24:MI:SS’) from dual; --加1分钟
select sysdate,to_char(sysdate+1/24/60/60,‘yyyy-mm-dd HH24:MI:SS’) from dual; --加1秒
select to_char(sysdate-1,‘yyyymmdd’) from dual;

–LAST_DAY(x):返回x这个时间值的最后一天
select to_char(sysdate,‘yyyy.mm.dd’),to_char((sysdate)+1,‘yyyy.mm.dd’) from dual;
select last_day(sysdate) from dual;

–MONTHS_BETWEEN(date2,date1)
–给出date2-date1的月份数
select months_between(‘19-12月-1999’,‘19-3月-1999’) mon_between from dual;
select months_between(to_date(‘2000.05.20’,‘yyyy.mm.dd’),to_date(‘2005.05.20’,‘yyyy.mm.dd’)) mon_betw from dual;
–用以计算x,y之间的月份差,若不是整月可以采用小数表示;
select months_between(sysdate,hiredate) from emp;

–NEW_TIME(date,‘this’,‘that’)
–给出在this 时区=other 时区的日期和时间
select to_char(sysdate,‘yyyy.mm.dd hh24:mi:ss’) bj_time,to_char(new_time(sysdate,‘PDT’,‘GMT’),‘yyyy.mm.dd hh24:mi:ss’) los_angles from dual;

–NEXT_DAY(date,‘day’)
–给出日期date 和星期x 之后计算下一个星期的日期
select next_day(‘19-5月-2001’,‘星期五’) next_day from dual;
–next_day(x,y)
–用于计算x时间后第一个星期y的时间,x是一个时间,y是星期一至星期日中的一个。也可能用数字1-7代替,但是用数字的时候1是代表的周日2才是代表的周一
select next_day(sysdate,‘星期一’) from dual;

–SYSDATE:用来得到系统的当前日期
select to_char(sysdate,‘dd-mm-yyyy day’) from dual;

–trunc(date,fmt)按照给出的要求将日期截断,如果fmt='mi’表示保留分,截断秒
select to_char(trunc(sysdate,‘hh’),‘yyyy.mm.dd hh24:mi:ss’) hh,to_char(trunc(sysdate,‘mi’),‘yyyy.mm.dd hh24:mi:ss’) hhmm from dual;

–CHARTOROWID:将字符数据类型转换为ROWID 类型
select rowid,rowidtochar(rowid),ename from scott.emp;

–ROWIDTOCHAR:将ROWID 数据类型转换为字符类型
select rowid,rowidtochar(rowid),ename from scott.emp;

–CONVERT(c,dset,sset)
–将源字符串sset 从一个语言字符集转化到另一个目的dset字符集
select convert(‘strutz’,‘we8hp’,‘f7dec’) conversion from dual;

–HEXTORAW:将一个十六进制构成的字符串转换为二进制

–RAWTOHEXT:将一个二进制构成的字符串转换为十六进制

–TO_CHAR(date,‘format’)
select to_char(sysdate,‘yyyy/mm/dd hh24:mi:ss’) from dual;
select to_char(sysdate,‘yyyy’) from dual;
select to_char(sysdate,‘fmyyyy-mm-dd’) from dual;
select to_char(sal,‘L999,999,999’) from emp;
select to_char(sysdate,‘D’) from dual;–返回星期

–TO_DATE(string,‘format’)
–将字符串转化ORACLE中的一个日期
Select to_date(‘20090210’,‘yyyyMMdd’) from dual;

–TO_MULTI_BYTE:将字符串中的单字节字符转为多字节字符
select to_multi_byte(‘高’) from dual;

–TO_NUMBER:将给出的字符转换为数字
select to_number(‘1999’) year from dual;
select to_number(‘13’)+to_number(‘14’) from dual;

–BFILENAME(dir,file)
–指定一个外部二进制文件
insert into file_tb1 values(bfilename(‘lob_dir1’,‘image1.gif’));

–CONVERT(‘x’,‘desc’,‘source’)
–将x 字段或变量的源source 转换为desc
select sid,serial#,username,decode(command,0,‘none’,2,‘insert’,3,‘select’,6,‘update’,7,‘delete’,8,‘drop’,‘other’) cmd from v$session where type!=‘background’;

–DUMP(s,fmt,start,length)
–以fmt 指定的内部数字格式返回一个varchar2 类型的值
col global_name for a30;
col dump_string for a50;
set lin 200;
select global_name,dump(global_name,1017,8,5) dump_string from global_name;

–EMPTY_BLOB() 和 EMPTY_CLOB()
–用来对大数据类型字段进行初始化操作的函数

–GREATEST:返回一组表达式中的最大值,即比较字符的编码大小
select greatest(‘AA’,‘AB’,‘AC’) from dual;
select greatest(‘啊’,‘安’,‘天’) from dual;

–LEAST:返回一组表达式中的最小值
select least(‘啊’,‘安’,‘天’) from dual;

–UID:返回标识当前用户的唯一整数
select username,user_id from dba_users where user_id = uid;

–USER:返回当前用户的名字
select user from dual;
–查询当前所有的用户
select * from dba_users;

–USEREVN:返回当前用户环境的信息
–opt可以是:ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZE
select userenv(‘isdba’) from dual;–ISDBA:查看当前用户是否是DBA,如果是则返回true
select userenv(‘sessionid’) from dual;–返回会话标志
select userenv(‘entryid’) from dual;–返回会话人标志
select userenv(‘instance’) from dual;–返回当前INSTANCE 的标志
select userenv(‘language’) from dual;–返回当前环境变量
select userenv(‘lang’) from dual;–返回当前环境的语言的缩写
select userenv(‘terminal’) from dual;–返回用户的终端或机器的标志
select vsize(user),user from dual;–返回X 的大小(字节)数

–AVG(DISTINCT|ALL)
–all 表示对所有值求平均值,distinct 表示只对不同值求平均值
create table table3(xm varchar(8),sal number(7,2));
insert into table3 values(‘gao’,1111.11);
insert into table3 values(‘gao’,1111.11);
insert into table3 values(‘zhu’,5555.55);
select avg(distinct sal) from gao.table3;
select avg(all sal) from gao.table3;
–avg()
–求平均值函数,用于对指定的列或表达式求平均值。如果该列存在空(NULL)值,则avg()函数会忽略该值。
select avg(comm) from emp;

–MAX (DISTINCT|ALL)
–求最大值,ALL表示对所有的值求最大值,DISTINCT 表示对不同的值求最大值
select max(distinct sal) from scott.emp;

–MIN(DISTINCT|ALL)
–求最小值,ALL表示对所有的值求最小值,DISTINCT 表示对不同的值求最小值
select min(all sal) from scott.emp;

–max()
–min()
–sum()
–对某一列操作
select max(sal) from emp;
select min(sal) from emp;
select sum(comm) from emp;

–STDDEV(DISTINCT|ALL)
–求标准差
select stddev(sal) from scott.emp;
select stddev(distinct sal) from scott.emp;

–VARIANCE(DISTINCT|ALL)
–求协方差
select variance(sal) from scott.emp;

–GROUP BY :用来对一组数进行统计
select deptno,count(*),sum(sal) from scott.emp group by deptno;
select max(empno),deptno from emp group by deptno;

–HAVING:对分组统计再加限制条件
select deptno,count(),sum(sal) from scott.emp group by deptno having count()>=5;
–一个表中的Id有多个记录,把所有这个id的记录查出来,并显示共有多少条记录数
select id, Count() from tb group by id having count()>1;
select deptno,count(),sum(sal) from scott.emp having count()>=5 group by deptno;
–找出平均工资小于1200的人信息
select deptno,job,avg(sal) from emp
where hiredate >= to_date(‘1981-05-01’,‘yyyy-mm-dd’)
group by deptno,job
having avg(sal) < 1200
order by deptno,job;

–ORDER BY 用于对查询到的结果进行排序输出
select deptno,ename,sal from scott.emp order by deptno,sal desc;
select * from student order by sight;将sight的值由低到高排序
select * from student order by sight desc;将sight的值由高到低排序
select * from student order by birth;将年龄从大到小排序(出生日期越小年龄越大)
select * from student where sex=’0’ order by birth desc;将男生的年龄从小到大排序输出

–count()
–如果数据库表的没有数据count()返回的不是null,而是0
–列出emp这张表中有多少行数据
select count(
) from emp;
select count () as 人数 from student;–给字段设别名;,若是有null行,他也会记录上去
select count (sno) as 人数 from student;–null行不会被记录上去
select count (
) as 男生人数 from student where sex=’0’;–显示男生人数

–分组函数嵌套
select max(avg(sal))
from emp
group by deptno;

–分组统计各部门下工资>500 的员工的平均工资、
Select avg(sal),deptno from emp where sal>500 group by deptno;
select deptno,avg(sal) from emp group by deptno having avg(sal)>500;

–算出部门 30 中得到最多奖金的员工奖金
select max(comm) from emp where deptno=30;

–算出部门 30 中得到最多奖金的员工姓名
select ename from emp where comm=(select max(comm) from emp where deptno=30);

–算出每个职位的员工数和最低工资
select job,min(sal),count(*) from emp group by job order by job;

–找出每个月倒数第三天受雇的员工(如:2009-5-29)
select * from emp where last_day(hiredate)-2=hiredate;

–找出 25 年前雇的员工
select * from emp where hiredate<=add_months(sysdate,-25*12);

–所有员工名字前加上 Dear ,并且名字首字母大写
select 'Dear '||initcap(ename) from emp;

–找出姓名为 5 个字母的员工
select * from emp where length(ename)=5;

–找出姓名中不带 R 这个字母的员工
select * from emp where ename not like ‘%R%’;

–显示所有员工的姓名的第一个字
select substr(ename,0,1) from emp;

–显示所有员工,按名字降序排列,若相同,则按工资升序排序
–desc表示降序,asc表示升序
select * from emp order by ename desc,sal asc;

–假设一个月为 30 天,找出所有员工的日薪,不计小数
select ename,trunc(sal/30) from emp;

–找到 2 月份受雇的员工
select * from emp where to_char(hiredate,‘fmmm’)=‘2’;

–列出员工加入公司的天数(四舍五入)
select ename,round(sysdate-hiredate) from emp;

/*
算出每个部门,每个职位的平均工资和平均奖金(平均值包括没有奖金),如果平均奖金大于 300,
显示“奖金不错”,如果平均奖金100到300,显示“奖金一般”,如果平均奖金小于 100,显示“基本没有奖金”,
按部门编号降序,平均工资降序排列
*/
select avg(sal),avg(nvl(comm,0)),case
when avg(nvl(comm,0))>300 then ‘奖金不错’
when avg(nvl(comm,0))>100 and avg(nvl(comm,0))<300 then ‘奖金一般’
when avg(nvl(comm,0))<100 then ‘基本没有奖金’
end 奖金状况
from emp group by job order by job desc,avg(sal) desc;

–列出员工表中每个部门的员工数,和部门 no
Select count(*),deptno from emp group by deptno;

–得到工资大于自己部门平均工资的员工信息
select * from emp e1,
(select deptno,avg(sal) as avgsal from emp group by deptno) e2
where e1.deptno=e2.deptno and e1.sal > e2.avgsal;

–分组统计每个部门下,每种职位的平均奖金(也要算没奖金的人)和总工资(包括奖金)
select deptno,job,avg(nvl(comm,0)),sum(sal+nvl(comm,0)) from emp group by deptno,job;

–连续求和
–sum(sal) over(order by ename)指的是连续求和.是以 ename 来排序的。若有两个这样的窗口函数,以后面的排序为主。
select ename,sal,sum(sal) over(), sum(sal) over(order by ename) from emp;

–分部门连续求和
– over(partition by deptno)按照部门分区
select deptno,sal ,sum(sal) over (partition by deptno order by ename) as s from emp;

–lead是向上移动
–lag是将这一行的数据向下移动后成为新一行的数据
SELECT c1,c2,rn,LAG (rn) OVER (PARTITION BY c1 ORDER BY rn) rn1 from (SELECT c1, c2, ROW_NUMBER () OVER (ORDER BY c1) rn FROM test_bgd) a;
–得到当前行上一行或者下一行的数据
–lead是得到下一行,lag得到上一行数据
select ename,sal,lead(sal) over(order by sal) aaa ,lag(sal) over(order by sal) bbb from emp;
–统计每个月及上月和下月的总收入,要求列表输出为,月份 当月收入 上月收入 下月收入
select month,sum( income),lead(sum( income)) over(order by sum( income)) from table group by month;

–自定义函数
CREATE OR REPLACE FUNCTION fun(sdate date,edate date) return number
as
s number;
begin
if(sdate < edate) then
s := 1;
else then
s:= 2;
end if;
return s;
end;

select fun(to_date(‘20140920’,‘yyyyMMdd’),to_date(‘20140919’,‘yyyyMMdd’)) as days from dual;


CREATE OR REPLACE FUNCTION HelloWorld4 return varchar
as
s varchar(20);
begin
s := ‘Hello World!’;
return s;
end;

SELECT HelloWorld4 from dual;


–查询指定时间段内一个时间段内的每个月,每人的工作天数
create table test_eap
(
cname varchar2(50),
startdate date,
enddate date
);

insert into test_eap values(‘aa’,to_date(‘20131222’,‘yyyyMMdd’),to_date(‘20140122’,‘yyyyMMdd’));
insert into test_eap values(‘aa’,to_date(‘20140102’,‘yyyyMMdd’),to_date(‘20140122’,‘yyyyMMdd’));
insert into test_eap values(‘aa’,to_date(‘20140103’,‘yyyyMMdd’),to_date(‘20140222’,‘yyyyMMdd’));
insert into test_eap values(‘aa’,to_date(‘20131222’,‘yyyyMMdd’),to_date(‘20140222’,‘yyyyMMdd’));
insert into test_eap values(‘bb’,to_date(‘20130122’,‘yyyyMMdd’),to_date(‘20140222’,‘yyyyMMdd’));


–1.
–查询一个时间段内的工作日天数
create or replace function calcDates(start_date date,end_date date) return number
is
days number;
begin
select sum(case when to_char(dayList,‘D’) not in (1,7) then 1 else 0 end) day_sum into days
from
(
select trunc(start_date) + level -1 dayList from dual connect by trunc(start_date) + level -1 <= trunc (end_date)
);
Return days;
END;

select to_number(cmonth) as cmonth,userid,sum(nvl(days,0)) as days
from
(
select cmonth,userid,sdate,edate,calcDates(start_inmonth,end_inmonth) as days
from
(
select tmonth.cmonth,my_message.*,
case
when my_message.sdate < to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’ ,‘yyyy/mm/dd’)
then to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’,‘yyyy/mm/dd’)
else my_message.sdate
end as start_inmonth,
case
when my_message.edate > add_months(to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’ ,‘yyyy/mm/dd’),1)
then add_months(to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’ ,‘yyyy/mm/dd’),1)
else my_message.edate
end as end_inmonth
from
(
select ‘1’ as cmonth from dual union all
select ‘2’ as cmonth from dual union all
select ‘3’ as cmonth from dual union all
select ‘4’ as cmonth from dual union all
select ‘5’ as cmonth from dual union all
select ‘6’ as cmonth from dual union all
select ‘7’ as cmonth from dual union all
select ‘8’ as cmonth from dual union all
select ‘9’ as cmonth from dual union all
select ‘10’ as cmonth from dual union all
select ‘11’ as cmonth from dual union all
select ‘12’ as cmonth from dual
) tmonth
left join
( select cname userid,trunc(startdate) sdate,trunc(enddate) edate from test_eap) my_message
on
my_message.edate > to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’,‘yyyy/mm/dd’)
and
my_message.sdate < add_months(to_date(to_char(to_date(‘20140101’,‘yyyyMMdd’),‘yyyy’) || ‘/’ || tmonth.cmonth || ‘/’ || ‘01’ ,‘yyyy/mm/dd’),1)
)
)
group by userid,cmonth;

–2.
–计算两个时间段间的工作日天数
select cname,
etime-btime+1 total_days,
trunc((etime-btime+1)/7)*5+length(replace(substr(‘01111100111110’,to_char(btime,‘D’),mod(etime-btime+1,7)),‘0’,’’)) as work_days
from
(
select cname,
trunc(startdate) as btime,
trunc(enddate) as etime
from
test_eap
where
startdate < to_date(‘20150101’,‘yyyyMMdd’)
and enddate > to_date(‘20140101’,‘yyyyMMdd’)
)


视图(View)---------------------------------------------------------------------
封装了一条select查询语句的数据库对象
特点:它将一条select查询语句的结果集当成一个临时表对待,可以对该临时表进行DQL和DML操作,使用方式跟表几乎一样,它就是一个虚拟表
作用:根据不同用户的需求对数据进行整理
基表:视图基于的表,也就是select查询语句使用的表

– 创建视图
–根据生日显示年龄
create or replace view stu_v (num,name,sex,age,phone)
as (select sno,sname,sex, to_number(to_char(sysdate,‘YYYY’))-to_number(to_char(birth,‘YYYY’)),phone from student);

select * from stu_v;

–对视图进行DML操作
–不建议对视图进行DML操作,简单的视图可以进行,Oracle不允许对复杂的视图进行DML操作,容易对数据的完整性进行破坏
update stu_v set name=‘夏侯惇’ where num=1007;

select * from student;

create or replace view cpp_score (sno,sname,sex,score) as
select st.sno,st.sname,st.sex,sc.score from student st,course,sc where st.sno=sc.sno and course.cno=sc.cno and cname=‘C程序设计’ order by sc.score desc;

select * from cpp_score;

–视图
–建立一个只包含 20 部门雇员信息的视图(雇员的编号、姓名、工资)
CREATE VIEW empv20(empno,ename,sal) AS SELECT empno,ename,sal FROM emp WHERE deptno=20 ;
select * from empv20;

–显示部门内最低工资比 20 部门最低工资要高的部门的编号及部门内最低工资:
SELECT deptno,MIN(sal) FROM emp GROUP BY deptno HAVING MIN(sal)>(SELECT MIN(sal) FROM emp WHERE deptno=20);
此时就可以将上面的复杂查询语句建立一张视图,之后查询视图即可。

–查询视图
select * from user_views;

–删除视图
DROP VIEW empv20 ;

–创建视图
CREATE OR REPLACE VIEW EMPV20(DEPTNO,MSAL) AS
(
SELECT DEPTNO,MIN(SAL) FROM EMP GROUP BY DEPTNO HAVING MIN(SAL)>(SELECT MIN(SAL) FROM EMP WHERE DEPTNO=20)
);

–创建一个只包含 20 部门的视图
CREATE OR REPLACE VIEW EMPV20(EMPNO,ENAME,SAL,DEPTNO) AS
SELECT EMPNO,ENAME,SAL,DEPTNO FROM EMP WHERE DEPTNO=20;

–现在直接更新视图里的数据
–将 7369 的部门编号修改为 30。此操作在视图中完成。
select * from empv20;
update empv20 SET deptno=30 where empno=7566 ;
–此时,提示更新完成。默认情况下创建的视图,如果更新了,则会自动将此数据从视图中删除,之后会更新原本的数据。

–更新视图数据
–如果能这样做的话,肯定存在问题,因为视图最好还是不要更新。
–在建立视图的时候有两个参数:
–1. WITH CHECK OPTION  保护视图的创建规则

CREATE OR REPLACE VIEW empv20 (empno,ename,sal,deptno) AS
SELECT empno,ename,sal,deptno FROM emp WHERE deptno=20
WITH CHECK OPTION CONSTRAINT empv20_ck;

–再执行更新操作:
–此处更新的是部门编号,失败
update empv20 SET deptno=30 where empno=7788 ;

–之前是按照部门编号建立的视图,所以不能修改部门编号
update empv20 SET ename=‘tom’ where empno=7876 ;  可以更新,更新的是名字,成功
select * from empv20;

–2. WITH READ ONLY(只读,不可修改),视图最好不要轻易的修改
CREATE OR REPLACE VIEW empv20(empno,ename,sal,deptno) AS
SELECT empno,ename,sal,deptno FROM emp WHERE deptno=20
WITH READ ONLY;
–现在任意的字段都不可更改,所以现在的视图是只读的。
–如果视图的基表有多行查询(比如:group by,distinct)那么该视图也是只读的

约束(Constraint)-----------------------------------------------------------------
对插入数据库的数据进行各种限制,以保证数据的完整性

约束分为五类:
非空约束(not null):约束的字段不能为NULL,Oracle认为空字符串(’’)也为NULL
唯一性约束(unique):字段值不能重复,NULL除外
主键约束(primary key):字段值不能为NULL,并且不能重复
外键约束(foreign key):被约束的字段的值受其他表字段的限制,不能随意,可以为NULL
检查约束(check):对字段的取值进行限制,可以为NULL,比如人的年龄介于0-200之间,不能是这个范围之外的值

定义约束的三种方式:
列级定义:在定义字段的时候定义约束
表级定义:在定义所有字段之后定义约束
表外定义:在表外定义,一般是对已经存在的表进行定义约束

–如果没有任何约束的话,不合法的数据也能插入数据库
insert into student (sname,phone,birth,sight) values (‘赵子龙’,‘12345678912’,‘1-1月-00’,9.3);

–主键--------------------------------------------------------------------
–可以为一个或者多个字段,用来唯一地标识每条记录,通常情况下每张表都应该设置主键
create table Person
(
id number(20) primary key,–表明id号不能同名
name varchar2(30) not null,–表明名字不能为空,未明确说表明可以相同
sex char not null check(sex in (‘0’,‘1’)), – 检查约束没有非空约束能力,只有检查约束的字段可以为NULL,除非加上非空约束
phone char(11) unique–表明这是唯一的
);
insert into Person(id,name,sex) values (1010,‘甘兴霸’,‘1’);
insert into Person(id,name,sex,phone) values (1003,‘黄月英’,‘0’,‘13645678912’);

–外键----------------------------------------------------------------------
create table Book
(
id number(8),
name varchar2(50) not null,
–Person中的id字段称为owner字段的父键(Parent Key),owner字段就是它的子键
–on delete cascade表示当他的父键被删除了那么他也会被删除
owner number(20) references person(id) on delete cascade,
constraint pk_book_id primary key(id)
);
insert into book values(2001, ‘C++程序设计’, 1003);
– 外键约束没有非空约束能力,只有外键约束的字段可以为NULL,除非再加上非空约束
insert into book values(2002, ‘C程序设计’, null);
insert into book (id,name) values(2003,‘Java程序设计’);

–默认值------------------------------------------------------------------
create table test
(
t1 number(10),
t2 number(8) default 1234 not null–设置默认值为1234
);
insert into test (t1) values (1000);–可以,没有显式指定t2的值,所以t2的值为默认值1234
insert into test (t1,t2) values (100,NULL);–这句代码是错的,显式指定t2为NULL,而不能为NULL
insert into test (t1,t2) values (101,default);–可以,显式让t2取默认值

–使用ALTER进行表外定义方式添加约束-------------------------------------------
–添加主键
alter table Student add constraint stu_id_pk primary key(sno);
–添加非空约束
alter table Student modify sname not null;
–用检查约束实现非空约束的效果
alter table Student add constraint stu_name_ck check(sname is not null);
–设置默认值为0
alter table Student modify sex default ‘0’;
alter table Student add constraint stu_sex_ck check (sex is not null and sex in (‘0’, ‘1’));
–唯一性
alter table Student add constraint stu_phone_uk unique(phone);
–检查值是否在设置值之间
alter table Student add constraint stu_sight_ck check(sight between 0 and 5);
alter table sc add constraint sc_score_ck check (score is not null and score between 0 and 100);
alter table student add constraint stu_cc_1 check((sage between 18 and 24) and ssex in ( ‘男’,‘女’));
alter table course add constraint cou_cc_2 check(cpno in (cno));
–设置外键
alter table SC add constraint sc_sno_fk foreign key (sno) references student(sno) on delete cascade;
alter table SC add constraint sc_score_ck check (score is not null) reference student(sno) on delete cascade;
–增加外键约束
alter table sc add constraint wj1 foreign key (sno) references student(sno);
–删除外键约束
alter table sc drop wj1;

–NOT NULL:非空约束
–姓名不能为空
CREATE TABLE person
(
pid NUMBER ,
name VARCHAR(30) NOT NULL
) ;
– 插入数据
INSERT INTO person(pid,name) VALUES (11,‘张三’);
– 错误的数据,会受到约束限制,无法插入

–PRIMARY KEY:主键约束
–不能重复,不能为空(设置为主键后就相当于设置了非空约束)
–身份证号不能为空。
DROP TABLE person ;
CREATE TABLE person
(
pid NUMBER PRIMARY KEY ,
name VARCHAR(30) NOT NULL
) ;
– 插入数据
INSERT INTO person(pid,name) VALUES (11,‘张三’);
– 主键重复了,便会报错
INSERT INTO person(pid,name) VALUES (11,‘李四’);

–UNIQUE:唯一约束,值不能重复(空值除外)
–人员中有电话号码,电话号码不能重复。
DROP TABLE person ;
CREATE TABLE person
(
pid NUMBER PRIMARY KEY NOT NULL ,
name NVARCHAR2(30) NOT NULL ,
tel NVARCHAR2(50) UNIQUE
) ;
– 插入数据
INSERT INTO person(pid,name,tel) VALUES (11,‘张三’,‘123456’);
– 电话重复了
INSERT INTO person(pid,name,tel) VALUES (12,‘李四’,‘123456’);

–CHECK:条件约束,插入的数据必须满足某些条件
–人员有年龄,年龄的取值只能是 0~150 岁之间
DROP TABLE person ;
CREATE TABLE person
(
pid NUMBER PRIMARY KEY NOT NULL ,
name VARCHAR(30) NOT NULL ,
tel VARCHAR(50) NOT NULL UNIQUE ,
age NUMBER CHECK(age BETWEEN 0 AND 150)
);
– 插入数据
INSERT INTO person(pid,name,tel,age) VALUES (11,‘张三’,‘1234567’,30);
– 年龄的输入错误
INSERT INTO person(pid,name,tel,age) VALUES (12,‘李四’,‘2345678’,-100);

–Foreign Key:外键
–一个人有很多本书:
–Person 表
–Book 表:而且 book 中的每一条记录表示一本书的信息,一本书的信息属于一个人
CREATE TABLE book
(
bid NUMBER PRIMARY KEY NOT NULL ,
name VARCHAR(50) ,
– 书应该属于一个人
pid NUMBER REFERENCES person(pid) ON DELETE CASCADE
– 建立约束: book_pid_fk,与 person 中的 pid 为主-外键关系
–CONSTRAINT book_pid_fk FOREIGN KEY(pid) REFERENCES person(pid)
) ;
–插入数据的时候pid必须在person表中存在
INSERT INTO book(bid,name,pid) VALUES(1001,‘JAVA’,12) ;

–在建立外键的时候必须指定级联删除(ON DELETE CASCADE)。
drop table book;
CREATE TABLE book
(
bid NUMBER PRIMARY KEY NOT NULL ,
name VARCHAR(50) ,
– 书应该属于一个人
pid NUMBER REFERENCES person(pid) ON DELETE CASCADE,
– 建立约束: book_pid_fk,与 person 中的 pid 为主-外键关系
–当person表中的这个pid数据被删除后,那么book表中对应的数据也会自动删除
CONSTRAINT book_pid_fk FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;

–Test
DROP TABLE book ;
DROP TABLE person ;
CREATE TABLE person
(
pid NUMBER ,
name VARCHAR(30) NOT NULL ,
tel VARCHAR(50) ,
age NUMBER
) ;
CREATE TABLE book
(
bid NUMBER ,
name VARCHAR(50) ,
pid NUMBER
) ;

–person 表 pid 为主键:
ALTER TABLE person ADD CONSTRAINT person_pid_pk PRIMARY KEY(pid) ;

–book 表 bid 为主键:
ALTER TABLE book ADD CONSTRAINT book_bid_pk PRIMARY KEY(bid) ;

–为 person 表中的 tel 添加唯一约束:
ALTER TABLE person ADD CONSTRAINT person_tel_uk UNIQUE(tel) ;

–为 person 表中的 age 添加检查约束:
ALTER TABLE person ADD CONSTRAINT person_age_ck CHECK(age BETWEEN 0 AND 150) ;

–为 book 表中的 pid 添加与 person 的主-外键约束,要求带级联删除
ALTER TABLE book ADD CONSTRAINT person_book_pid_fk FOREIGN KEY (pid) REFERENCES person(pid) ON DELETE CASCADE ;

–用 alter 添加非空约束
alter table book modify name constraint name_not_null not null;

–删除约束:
ALTER TABLE book DROP CONSTRAINT person_book_pid_fk ;
alter table person drop unique(tel);

–启用约束
ALTER TABLE book enable CONSTRAINT person_book_pid_fk ;

–禁用约束
ALTER TABLE book disable CONSTRAINT person_book_pid_fk;

–Test
create table student
(
id number,
name varchar2(10),
age number(10),
tel varchar2(10)
);

insert into student values(1,‘aa’,20,‘123456789’);
select * from student;
–给 id 字段添加主键约束
alter table student add constraint student_id_pk primary key(id);

–给 name 字段添加非空约束
alter table student modify name constraint student_name_not_null not null;

–给 age 字段添加 check 约束( age 必须大于 18 岁 )
alter table student add constraint student_age_ck check(age between 18 and 150);

–给 tel 添加唯一 非空 约束
alter table student add constraint student_tel_uk unique(tel);

–或者直接在创建表的时候这样加上条件
create table student(
id number primary key,
name varchar2(10) not null,
age number(10) check(age > 18),
tel varchar2(10) unique not null
);

create table hobby
(
id number(10),
hobby_name varchar2(10),
sid number
);

–给 sid 字段添加外键约束,并且要带级联删除
alter table hobby add constraint hobby_id_fk foreign key(id) references student(id) on delete cascade;

–或者直接在创建表的时候这样加上条件
create table hobby(
id number(10),
hobby_name varchar2(10),
sid number references student(id) on delete cascade
);

–删除掉 student 表中 tel 字段的唯一约束(先写出查看该表约束的 sql)
select constraint_name, constraint_type from all_constraints where table_name = upper(‘student’);
alter table student drop unique(tel);

–手动添加 student 表中 tel 字段的唯一约束(约束名为: MY_CONSTRAINT_1)
alter table student add constraint MY_CONSTRAINT_1 unique(tel);

–禁用约束 MY_CONSTRAINT_1
alter table student disable constraint MY_CONSTRAINT_1;

–启用约束 MY_CONSTRAINT_1
alter table student enable constraint MY_CONSTRAINT_1;

序列(Sequence)-----------------------------------------------------------------
主要用于实现自增长字段

–创建序列
create sequence sq_sno
start with 1001 --序列起始值
increment by 1 --增长步长
maxvalue 99999999 --序列最大值
cycle --cycle表示循环达到最大值后从初始值开始增长,nocycle表示不循环,达到最大值后出错
nocache;–nocache表示不缓存,效率低但是可以保证序列值连续,要缓存的话可使用cache 20 表示缓存20个值

–在创建序列后要先使用nextval后才能使用currval,否则会发生未定义的错误
select sq_sno.nextval from dual;
select sq_sno.currval from dual;

insert into student values (sq_sno.nextval,‘夏侯渊’,‘2-3月-93’,‘12345696325’,5.2,‘1’);

drop sequence sq_sno; – 删除序列

–创建序列
Create sequence myseq
Start with 1
Increment by 1
Order
cache 20
Nocycle;
–用了 nocycle,就可以确保当该序列用于多张表的时候, ID 是唯一的
– create sequence 的时候用 nocache 防止跳号,跳号会导致

–不能改变当前值,但是可以改变增量
–使它每次增加3
Alter sequence myseq increment by 3;

–NextVal,CurrVal
Select myseq.nextval from dual;–依次顺序显示值
Select myseq.currval from dual;
–(必须先有 nextval,才能有 currval)

–Cycle, Cache
create sequence myseq2 start with 1 increment by 1 cycle maxvalue 3 nocache ;
–这样到 3 之后,要会重新从 1 开始

–Dual 其实是 sys 用户下的一张表
select table_name from user_tables where lower(table_name) = ‘dual’;

Create synonym dept for soctt.dept;–(这样创建的同义词是私有的,只有创建者才能用)
Drop synonym dept;
Create public synonym dept for soctt.dept;–(这样创建的同义词才是公有的)
Drop public synonym dept;

–创建一个包含 1982 年 3 月 31 日以后入职的所有雇员的视图
create or replace view empv10 as
(
select * from emp where hiredate > to_date(‘19820331’,‘yyyymmdd’)
)

–创建一个包含佣金高于其薪金的雇员视图
create or replace view empv20 as
(
select * from emp where nvl(comm,0)>sal
)

–创建一个包含所有雇员的雇员编号、雇员名称、部门名称和薪金的视图
create or replace view empv30 as
(
select e.empno,e.ename,e.sal,d.dname from emp e,dept d where d.deptno=e.deptno
)

–创建一个有手下的雇员的视图,包括雇员编号,雇员名称
create or replace view empv40 as
(
select empno,ename from emp where empno not in(select empno from emp where empno in(select mgr from emp))
)

–创建一个包含各种工作的薪金总和的视图
create or replace view empv50 as
(
select sum(sal) as ssal from emp group by job
)

–创建一个序列,从 50 开始,每次增加 10
create sequence myseq
Start with 50
Increment by 10
Order
cache 20
Nocycle;

–用上面的序列给 dept 表加一条数据
insert into dept(deptno) values(myseq.nextval);

–为 emp 表创建一个同义词 emp1
create public synonym emp505 from scott.emp;

–在上面创建的同义词中插入值,并观察对基表的影响
insert into emp505(empno) values(myseq.nextval);
–在同义词上增加数据后,基表也会相应的增加数据

–在 emp 表的 empno 字段上创建一个索引,并检查是否可以创建
create index a123 on emp(empno)
–empno已经存在索引,所以不能再建立索引

–在 emp 表的 sal 上创建一个索引
create index pk_sal on emp(sal)

–列出您所创建的全部视图、同义词、序列和索引。

–删除你所创建的任何视图的基表,然后尝试查询视图,并观察查询的输出情况
drop table emp;

–删除您创建的所有视图、同义词、序列和索引。
–基表被删除后,同义词表也就不能使用了
drop public synonym emp505;–删除同义词
drop index pk_sal;–删除索引
drop view empv20;–删除视图
drop sequence myseq;–删除序列

索引(Index)-------------------------------------------------------------------
用于提高数据检索效率的数据库对象
DBMS会自动为主键或者唯一键创建索引,大多数情况下不需要我们亲自创建

–第十六章 索引-------------------------------------------------------------
select * from user_indexes --查询现有的索引
select * from user_ind_columns --可获知索引建立在那些字段上

–使用索引的条件
/*在 select 操作占大部分的表上创建索引;
在 where 子句中出现最频繁的列上创建索引;
在选择性高的列上创建索引(补充索引选择性,最高是 1 , eg: primary key)
复合索引的主列应该是最有选择性的和 where 限定条件最常用的列,并以此类推第二列
小于 5M 的表,最好不要使用索引来查询,表越小,越适合用全表扫描。
尽量不使用这些操作is null ; is not null ; not in; !=; like ;
numeric_col+0;date_col+0; char_col||’ '; to_char; to_number, to_date 等。
*/

–创建索引
create index abc on student(sid,sname);
create index abc1 on student(sname, sid);
/*
这两种索引方式是不一样的
索引 abc 对 Select * from student where sid=1; 这样的查询语句更有效
索引 abc1 对 Select * from student where sname=‟louis‟; 这样的查询语句更有效
因此建立索引的时候,字段的组合顺序是非常重要的。一般情况下,需要经常访问的字段
放在组合字段的前面
*/

–删除索引
drop index PK_DEPT1;

同义词(Synonym)------------------------------------------------------------------------------------------
表或视图的别名

很方便的操作不同用户下的对象,能使两个应用程序使用不同的名字指向同一张表,使用不同的用户指向同一张表的。,在任何一个用户下,都可以直接访问 dual,而不需要加上前缀的用户名,Dual 其实是 sys 用户下的一张表,因为同义词的存在,所以可以这样做

Create synonym dept for soctt.dept;(这样创建的同义词是私有的,只有创建者才能用)
Drop synonym dept; – 删除私有同义词
Create public synonym dept for soctt.dept;(这样创建的同义词才是公有的)
Drop public synonym dept; – 删除公有同义词

–触发器(Trigger)-------------------------------------------------------------
在某个事件发生时Oracle系统自动执行的过程,它也是一种数据库对象
–从事件源的角度分为:DDL触发器,DML触发器,系统事件触发器等
–从作用级别角度分为:行级触发器,语句级触发器

– 语句级触发器
create or replace trigger tr_del_stu
before delete on student
begin
–dbms_output.put_line(‘del!’);
raise_application_error(-20001,‘禁止删除!’);
end;

delete from student;

rollback;

select * from student;

drop trigger tr_del_stu;

–行级触发器
create or replace trigger tr_sc_insert
before insert on sc
for each row
begin
if:new.score<60 and :new.score:=1003 then
:new.score:=61;
raise_application_error(-20002,‘禁止不及格!’);
end if;
end;

insert into student values (null,‘典恶来’,‘7-9月-91’,‘18512365412’,5.0,‘0’);

create sequence sq_stu_id start with 1008 increment by 1;
maxvalue 9999999 cycle nocache;

create or replace trigger tr_student_insert
before insert on student
for each row
begin
dbms_output.put_line(‘test’);
select sq_stu_id.nextval into :new.sno from dual;
end;

–语句触发器
–Before 语句触发器
–禁止工作人员在休息日改变雇员信息
create or replace trigger tr_src_emp
before
insert or update or delete on emp
begin
if to_char(sysdate,‘DY’,‘nls_date_language=AMERICAN’) in( ‘SAT’,‘SUN’) then
raise_application_error(-20001,‘can‟t modify user information in weekend’);
end if;
end;
/
–raise_application_error是将应用程序专有的错误从服务器端转达到客户端应用程序(其他机器上的SQLPLUS或者其他前台开发语言)

–使用条件谓语
create or replace trigger tr_src_emp
before
insert or update or delete on emp
begin
if to_char(sysdate,‘DY’) in( ‘星期六’,‘星期天’) then
case
when inserting then
raise_application_error(-20001,‘fail to insert’);
when updating then
raise_application_error(-20001,‘fail to update’);
when deleting then
raise_application_error(-20001,‘fail to delete’);
end case;
end if;
end;
/

–after 语句触发器
–为了统计在 EMP 表上的增、删、改的次数。先建一张表
Create table audit_table(Name varchar2(20),ins int,upd int,del int,starttime date,endtime date);
–然后建立触发器
Create or replace trigger tr_audit_emp
After
insert or update or delete on emp Declare v_temp int;
Begin
Select count(*) into v_temp from audit_table Where name=‘EMP’;
If v_temp=0 then
Insert into audit_table values(‘EMP’,0,0,0,sysdate,null);
End if;
Case
When inserting then
Update audit_table set ins=ins+1,endtime=sysdate where name=‘EMP’;
When updating then
Update audit_table set upd=upd+1,endtime=sysdate where name=‘EMP’;
When deleting then
Update audit_table set del= del +1 ,endtime=sysdate where name=‘EMP’;
End case;
End;
/

–行触发器
–执行 DML 操作时,每作用一行就触发一次触发器。
–Bofre 行触发器
–确保员工工资不能低于原有工资
Create or replace trigger tr_emp_sal
before
update of sal on emp for each row
begin
if :new.sal < :old.sal then
raise_application_error(-20010,‘sal should not be less’);
end if;
end;
/

–after 行触发器
–统计员工工资变化
Create table audit_emp_change(Name varchar2(10),Oldsal number(6,2),Newsal number(6,2),Time date);
Create or replace trigger tr_sal_sal
after
update of sal on emp for each row declare v_temp int;
begin
select count(*) into v_temp from audit_emp_change where name=:old.ename;
if v_temp=0 then
insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
else
update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
end if;
end;
/

–限制行触发器
Create or replace trigger tr_sal_sal
after
update of sal on emp for each row when (old.job=‘SALESMAN’)
declare
v_temp int;
begin
select count(*) into v_temp from audit_emp_change where name=:old.ename;
if v_temp=0 then
insert into audit_emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
else
update audit_emp_change set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
end if;
end;
/

–编写 DML 触发器的时,触发器代码不能从触发器所对应的基表中读取数据。
–例如:如果要基于 EMP 表建立触发器。那么该触发器的执行代码不能包含对 EMP 表的查询操作。
Create or replace trigger tr_emp_sal
Before
update of sal on emp For each row
declare
Maxsal number(6,2);
Begin
Select max(sal) into maxsal from emp;
If :new.sal>maxsal then
Raise_application_error(-21000,‘error’);
End if;
End;
/

–创建的时候不会报错。但是一旦执行就报错了
update emp set sal=sal*1.1 where deptno=30;

–触发器的主要用途:控制数据安全
–在非工作时间不能对 EMP 表做操作
create or replace trigger tr_emp_time
before
insert or update or delete on emp
begin
if to_char(sysdate,‘HH24’) not between ‘9’ AND ‘17’ THEN
raise_application_error(-20101,‘not work time’);
end if;
end;
/

–实现数据统计
–上面提到的记载员工的工资变化等
–实现数据的完整性

–如果只是限制员工的工资不能低于 800,可以选用 check 约束
Alter table emp add constraint ck_sal check(sal>=800);

–但如果是限定新工资不能低于其原来工资,也不能高于 20%。则通过约束是无法实现的。这时可通过触发器来实现
Create or replace trigger tr_check_sal
Before
update of sal on emp For each row When(new.sal<old.sal or new.sal>1.2*old.sal);
Begin
Raise_application_error(-20931,‘ddd’);
End;
/

–实现参照完整性
–约束可实现级联删除,却不能实现级联更新,可通过触发器实现
Create or replace trigger tr_update_cascade
after
update of deptno on dept for each row
begin
update emp set deptno=:new.deptno where deptno=:old.deptno;
end;
/

–常用的事件属性函数如下:
–建立系统事件触发器时,需要使用事件属性函数
/*
Ora_client_ip_address 返回客户端的ip地址
Ora_database_name 返回当前数据库名
Ora_des_encrypted_password 返回des加密后的用户口令
Ora_dict_obj_name 返回ddl操作所对应的数据库对象名
Ora_dict_obj_name_list(name_list out ora_name_list_t) 返回在事件中被修改的对象名列表
Ora_dict_obj_owner 返回ddl操作所对应的对象的所有者名
Ora_dict_obj_owner_list(owner_list out ora_name_list_t) 返回在事件中被修改的对象的所有者列表
Ora_dict_obj_type 返回ddl操作所对应的数据库对象的类型
Ora_grantee(user_list out ora_name_list_t) 返回授权事件的授权者
Ora_instance_num 返回例程号
Ora_is_alter_column(column_name in varchar2) 检测特定列是否被修改
Ora_is_creating_nested_table 检测是否正在建立嵌套表
Ora_is_drop_column(column_name in varchar2) 检测特定列是否被删除
Ora_is_servererror(error_number) 检测是否返回了特定oracle错误
Ora_login_user 返回登录用户名
Ora_sysevent 返回触发器的系统事件名
*/

–启动/关闭触发器
–例程启动/关闭触发器只有特权用户才能建立,
–例程启动触发器只能使用after关键字
–例程关闭触发器只能使用before关键字

conn sys/oracle as sysdba
create table event_table(event varchar2(30),time date);

create or replace trigger tr_startup
after
startup on database
begin
insert into event_table values(ora_sysevent,sysdate);
end;
/

create or replace trigger tr_shutdown
before
shutdown on database
begin
insert into event_table values(ora_sysevent,sysdate);
end;
/

–在建立了触发器tr_startup之后,当打开数据库之后,会执行该触发器的相应代码
–在建立了触发器tr_shutdown之后,在关闭例程之前,会执行该触发器的相应代码,但shutdown abort命令不会触发该触发器
–示例
shutdown
startup
select event,to_char(time,‘YYYY/MM/DD HH24:MI’) time from event_table;

–登陆/退出触发器
–需要建立专门存放登录和退出的信息表log_table来记载登录用户和退出用户的名称、时间和IP地址
–示例
conn sys/oracle as sysdba
create table log_table(username varchar2(20),logon_time date,logoff_time date,address varchar2(20));

–登录/退出触发器一定要以特权用户身份建立
–示例
create or replace trigger tr_logon
after logon on database
begin
insert into log_table(username,logon_time,address) values(ora_login_user,sysdate,ora_client_ip_address);
end;
/

create or replace trigger tr_logoff
before logoff on database
begin
insert into log_table(username,logoff_time,address) values(ora_login_user,sysdate,ora_client_ip_address);
end;
/

–在建立触发器tr_logon之后,当用户登录到数据库之后,会执行其触发器代码
–在建立触发器tr_logoff之后,当用户断开数据库连接之前,会执行其触发器代码
–示例:
conn scott/tiger@orcl
conn system/manager@orcl
conn sys/oracle@orcl as sysdba
select * from log_table;

–DDL触发器
–专门用来记载DDL时间(CREATE,ALTER,DROP等)
conn sys/oracle as sysdba;
create table event_ddl(event varchar2(20),username varchar2(10),owner varchar2(10),objname varchar2(20),objtype varchar2(10),time date);
–建立DDL触发器,必须使用AFTER关键字
–示例:
create or replace trigger tr_ddl
after ddl on scott.schema
begin
insert into event_ddl values(ora_sysevent,ora_login_user,ora_dict_obj_owner,ora_dict_obj_name,ora_dict_obj_type,sysdate);
end;
/

–建立了触发器tr_ddl之后,如果在scott方案对象上执行了ddl操作,会将信息记载到表event_ddl中
–示例:
conn scott/tiger
create table temp(cola int);
drop table temp;
select event,owner,objname from event_ddl;

–管理触发器

–显示触发器信息
–可以通过查询数据字典user_triggers显示当前用户所包含的所有触发器信息
–示例:
conn scott/tiger
select trigger_name,status from user_triggers where table_name = ‘EMP’;

–禁止触发器
–就是让触发器临时失效,目的是为了加快操作数据的速度
alter trigger tr_check_sal disable;

–激活触发器
alter trigger tr_check_sal enable;

–禁止/激活表的所有触发器
alter table emp disable all triggers;
alter table emp enable all triggers;

–重新编译触发器
alter trigger tr_check_sal compile;

–删除触发器
drop trigger tr_check_sal;

–函数(Function):执行一系列操作,返回特定值------------------------------------
–函数形参和返回值类型都不能带精度
–函数形参分为三类:输入参数(默认),输出参数,输入输出参数
–创建函数后查看函数

create or replace function get_name(s_no number,s_sight out number,phone in out char) return nvarchar2
as
s_name nvarchar2(10);
begin
–select st.sname sight into s_name,s_sight from student st where st.sno=s_no;
select st.sname into s_name from student st where st.sno=s_no;
s_sight:=5.5;
phone:=substr(phone,0,3);

   return s_name;

end;

declare
sight number;
s_name nvarchar2(10);
phone char(11);
begin
phone:=‘123456’;
s_name:=get_name(1001,sight,phone);
dbms_output.put_line(s_name ||’ ‘||sight||’ '||phone);
end;

–删除函数
drop function get_name;

create or replace function get_name(s_no number) return nvarchar2
as
s_name nvarchar2(10);
begin
select st.sname into s_name from student st where st.sno=s_no;
return s_name;
end;

select get_name(1003) from dual;

–此函数可以根据雇员的编号查询出雇员的年薪
CREATE OR REPLACE FUNCTION myfun(eno emp.empno%TYPE) RETURN NUMBER
AS
rsal NUMBER ;
BEGIN
SELECT (sal+nvl(comm,0))*12 INTO rsal FROM emp WHERE empno=eno ;
RETURN rsal ;
END ;
/

SELECT myfun(7369) FROM dual ;

set serveroutput on
–使用游标 和 loop 循环来显示所有部门的名称
DECLARE
CURSOR mycur IS SELECT * FROM dept ;
deptInfo dept%ROWTYPE ;
BEGIN
– 游标操作使用循环,但是在操作之前必须先将游标打开
IF mycur%ISOPEN THEN
null ;
ELSE
OPEN mycur ;
END IF ;
LOOP
– 使游标向下一行
FETCH mycur INTO deptInfo ;
EXIT WHEN mycur%NOTFOUND ;
DBMS_OUTPUT.put_line('部门名称: '||deptInfo.dname) ;
END LOOP ;
END ;
/

set serveroutput on
–使用游标和while循环来显示所有部门的的地理位置(用%found属性)
declare
–游标声明
cursor csr_TestWhile
is
–select语句
select LOC from Dept;
–指定行指针
row_loc csr_TestWhile%rowtype;
begin
–打开游标
open csr_TestWhile;
–给第一行喂数据
fetch csr_TestWhile into row_loc;
–测试是否有数据,并执行循环
while csr_TestWhile%found loop
dbms_output.put_line(‘部门地点:’||row_loc.LOC);
–给下一行喂数据
fetch csr_TestWhile into row_loc;
end loop;
close csr_TestWhile;
end;
/

set serveroutput on
–用更新游标来为雇员加佣金(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来
declare
cursor
csr_Update
is
select * from emp for update OF SAL;
empInfo csr_Update%rowtype;
saleInfo emp.SAL%TYPE;
begin
FOR empInfo IN csr_Update LOOP
IF empInfo.SAL<1500 THEN
saleInfo:=empInfo.SAL1.2;
elsif empInfo.SAL<2000 THEN
saleInfo:=empInfo.SAL
1.5;
elsif empInfo.SAL<3000 THEN
saleInfo:=empInfo.SAL*2;
END IF;
UPDATE emp SET SAL=saleInfo WHERE CURRENT OF csr_Update;
END LOOP;
END;
/

set serveroutput on
–对名字以‘ A’或‘ S’开始的所有雇员按他们的基本薪水的10%给他们加薪
declare
cursor
csr_AddSal
is
select * from emp where ENAME LIKE ‘A%’ OR ENAME LIKE ‘S%’ for update OF SAL;
r_AddSal csr_AddSal%rowtype;
saleInfo emp.SAL%TYPE;
begin
for r_AddSal in csr_AddSal loop
dbms_output.put_line(r_AddSal.ENAME||‘原来的工资:’||r_AddSal.SAL);
saleInfo:=r_AddSal.SAL*1.1;
UPDATE emp SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
end loop;
end;
/

set serveroutput on
–编写一个 PL/SQL 程序块,对所有的 salesman 增加佣金 500
declare
cursor
csr_AddComm(p_job nvarchar2)
is
select * from emp where JOB=p_job FOR UPDATE OF COMM;
r_AddComm emp%rowtype;
commInfo emp.comm%type;
begin
for r_AddComm in csr_AddComm(‘SALESMAN’) LOOP
commInfo:=r_AddComm.COMM+500;
UPDATE EMP SET COMM=commInfo where CURRENT OF csr_AddComm;
END LOOP;
END;
/

set serveroutput on
–编写一个 PL/SQL 程序块,以提升 2 个资格最老的职员为高级职员(工作时间越长,资格越老)
–可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。
declare
cursor crs_testComput
is
select * from emp order by HIREDATE asc;
–计数器
top_two number:=2;
r_testComput crs_testComput%rowtype;
begin
open crs_testComput;
FETCH crs_testComput INTO r_testComput;
while top_two>0 loop
dbms_output.put_line(‘员工姓名:’||r_testComput.ENAME||’ 工作时间:’||r_testComput.HIREDATE);
–计速器减一
top_two:=top_two-1;
FETCH crs_testComput INTO r_testComput;
end loop;
close crs_testComput;
end;
/

–写一个函数 输入一个员工名字,判断该名字在员工表中是否存在。存在返回 1,不存在返回 0
create or replace function empfun(en emp.ename%type) return number
as
is_exist number;
begin
select count(*) into is_exist from emp where ename=upper(en);
return is_exist;
end;
/

–写一个函数,传入员工编号,返回所在部门名称
create or replace function myfun(eno emp.empno%type) return varchar
as
name varchar(30);
begin
select d.dname into name from emp e,dept d where e.deptno = d.deptno and e.empno = eno;
return name;
end;
/

–写一个函数,传入时间,返回入职时间比这个时间早的所有员工的平均工资
create or replace function getAvgSal(hdate emp.hiredate%type) return number
as
esal number;
begin
select avg(sal) into esal from emp where hdate>emp.hiredate;
return esal;
end;
/

–删除一张表重复记录( ID 是自增唯一,重复记录:其他字段都是一样)非常经典的一道面试题(可能存在很多数据,要求性能比较高)
aa
id name age
1 louis 20
2 louis 20
3 jimmy 30
4 louis 20


delete from aa where id not in(select min(id) from aa group by name,age);

delete test where id in (select distinct t2.id from test t1,test t2 where t1.id<t2.id and t1.name=t2.name and t1.age=t2.age);

delete test where id in (select distinct t1.id from test t1,test t2 where t1.id<t2.id and t1.name=t2.name and t1.age=t2.age);

create table tmp as select distinct name ,age from aa;
–快速清空表中数据
truncate table aa; --truncate 语句执行速度快,占资源少,并且只记录页删除的日志;
delete 对每条记录的删除均需要记录日志

insert into aa select * from tmp;
drop table tmp;

create table tmp as select * from aa where 1=2;
DECLARE
CURSOR mycur IS select * from aa order by id;
a1 aa%rowtype;
cou number;
begin
for a1 in mycur loop
select count(*) into cou from tmp where name=a1.name and age=a1.age;
if cou=0 then
insert into tmp values(a1.id,a1.name,a1.age);
else
delete from aa where id = a1.id;
end if;
end loop;
end;
/


DECLARE
CURSOR mycur IS select * from aa order by id;
a1 aa%rowtype;
cou number;
begin
for a1 in mycur loop
select count(*) into cou from tmp where name=a1.name and age=a1.age;
if cou=0 then
insert into tmp values(a1 .id,a1.name,a1.age);
end if;
end loop;
delete from aa;
insert into aa select * from tmp;
end;
/

–存储过程(Procedure)---------------------------------------------------------
没有返回值的函数,用于执行一系列操作的数据库对象
–过程:执行一系列操作的普通PL/SQL块,并不持久化存放在Oracle数据库服务器中,而存储过程跟其他数据库对象(表、视图、序列等)一样持久化存放在数据库服务器中
–创建过程后查看存储过程编译错误:show errors procedure my_add

create or replace procedure my_add
is
i number;
sum1 number:=0;
begin
for i in 1…100 loop
sum1:=sum1+i;
end loop;
dbms_output.put_line(sum1);
end;

–在SQL*Plus中可以使用exec命令调用存储过程,比如exec my_add
–在PL/SQL块中调用存储过程
begin
my_add;
end;

create or replace procedure m_add(i number,j number)
is
k number;
begin
k:=i+j;
dbms_output.put_line(k);
end;

begin
m_add(2,3);
end;

create or replace procedure my_add(n number,s out number)
is
i number;
sum1 number:=0;
begin
for i in 1…n loop
sum1:=sum1+i;
end loop;
–dbms_output.put_line(sum1);
s:=sum1;
end;

– 在SQL*Plus中可以使用exec命令调用存储过程,比如exec my_add
– 在PL/SQL块中调用存储过程

declare
sum1 number;
begin
my_add(100,sum1);
dbms_output.put_line(‘从一加到一百的和为:’||sum1);
end;

create or replace procedure get_stu_info(s_no number,s_name out nvarchar2,s_sight out number)
as
begin
select sname,sight into s_name,s_sight from student where sno=s_no;
exception
when no_data_found then
– 将异常交给调用者去处理,自定义错误编号的范围[-20999,-20000],范围之外的系统保留使用
raise_application_error(-20001,‘学号不存在’);
end;

declare
sno number(8);
sname nvarchar2(10);
sight number(2,1);
begin
sno:=&学号;
get_stu_info(sno,sname,sight);
dbms_output.put_line(‘学号:’||sno||’ 姓名:’||sname||’ 视力:’||sight);
end;

create or replace trigger tr_del_stu
before delete on student
begin
–dbms_output.put_line(‘del!’);
raise_application_error(-20001,‘禁止删除!’);
end;

–删除表中的信息
create or replace procedure del_stu(s_no number,del_cnt out number)
as
begin
delete from student where sno=s_no;
del_cnt:=SQL%ROWCOUNT;
end;

declare
del_cnt number;
sno number(8);
begin
sno:=&学号;
del_stu(sno,del_cnt);
dbms_output.put_line(‘删除’||del_cnt||‘个学生!’);
end;

rollback;

–创建一个可以向emp表中插入一行的过程
CREATE OR REPLACE PROCEDURE pro_c
AS
BEGIN
INSERT INTO emp V ALUES(8902,‘FORD’,‘ANALYST’,7566,to_date(‘1981-12-3’,‘yyyy-MM-dd’),3000.00,null,20);
END;
/

–创建一个过程,传入雇员名,返回该雇员的薪水(薪金+佣金)
CREATE OR REPLACE PROCEDURE pro_2(names VARCHAR2,sals OUT NUMBER )
AS
BEGIN
SELECT sal+nvl(comm,0) INTO sals FROM emp WHERE ename=names;
END;

–调用存储过程
DECLARE
sa NUMBER;
BEGIN
pro_2(‘SCOTT’,sa);
dbms_output.put_line(‘薪水为:’||pro_2(‘SCOTT’,sa));
END;
/

–创建一个过程,传入雇员号,和薪水及增长比例(10%=0.1)。其中薪水为in out参数!
–更新薪水为新薪水用一个PL/SQL程序块来调用此过程,其传入到过程中的参数都是用户输入得到的
CREATE OR REPLACE PROCEDURE pro_3(num NUMBER,sal IN OUT NUMBER,increase NUMBER)
AS
BEGIN
UPDATE emp SET sal=sal*(1+increase) WHERE empno=num;
COMMIT;
SELECT sal INTO sal FROM emp WHERE empno=num;
END;

–调用存储过程
DECLARE
num NUMBER;
incre NUMBER;
sal NUMBER;
BEGIN
pro_3(&num,sal,&incre);
dbms_output.put_line(‘薪水为:’||sal);
END;
/

–编写一个函数,以deptno为标准,返回此部门所有雇员的整体薪水
CREATE OR REPLACE Function fff_4 RETURN NUMBER
IS
CURSOR cu IS SELECT deptno d,SUM(sal) co FROM emp GROUP BY deptno;
BEGIN
FOR i IN cu LOOP
dbms_output.put_line(i.co||‘部门’||i.d);
END LOOP;
RETURN 0;
END;

–调用存储过程
DECLARE
num NUMBER;
BEGIN
num:=fff_4;
END;
/

–编写一个函数,接收deptno,和name(out),返回此部门的名称和地址
CREATE OR REPLACE Function f_5(num NUMBER) RETURN dept%ROWTYPE
IS
de dept%ROWTYPE;
BEGIN
SELECT * INTO de FROM dept WHERE deptno=num;
RETURN de;
END;

–调用存储过程
DECLARE
de dept%ROWTYPE;
BEGIN
de:=f_5(10);
dbms_output.put_line(de.DNAME||de.loc);
END;
/

–编写一个过程以显示所指定雇员名的雇员部门名和位置
CREATE OR REPLACE PROCEDURE p_6(name Varchar2,de OUT dept%ROWTYPE)
IS
BEGIN
select * INTO de from dept where deptno=(select deptno from emp where ename=name);
END;

–调用存储过程
DECLARE
de dept%ROWTYPE;
BEGIN
p_6(‘SCOTT’,de);
dbms_output.put_line(de.DNAME||’ '||de.loc);
END;
/

–编写一个给特殊雇员加薪10%的过程,这之后,检查如果已经雇佣该雇员超过了60个月,则给他额外加薪300。
CREATE OR REPLACE PROCEDURE p_7
IS
CURSOR cu IS SELECT * FROM emp FOR UPDATE;
BEGIN
FOR i IN cu LOOP
UPDATE emp SET sal=sal*1.1 WHERE CURRENT OF cu;
IF months_between(sysdate,i.hiredate)>60 THEN
UPDATE emp SET sal=sal+300 WHERE CURRENT OF cu;
END IF;
END LOOP;
END;
–调用存储过程
exec p_7;

–编写一个函数一检查所指定雇员的薪水是否在有效范围内,
–不同职位的薪水范围为:clerk 1500-2500 salesman 2501-2500 analyst 3501-4500 others 4501-n
CREATE OR REPLACE PROCEDURE(NAME VARCHAR2) p_8
IS
sa NUMBER;
job Varchar2(20);
BOOLEAN flag:=false;
BEGIN
SELECT sal,job INTO sa,job FROM emp WHERE ename=NAME;
IF job='CLERK’AND sal>=1500 AND sal<=2500 THEN
flag=TRUE;
ELSIF job='SALESMAN’AND sal>=1500 AND sal<=2500 THEN
flag=TRUE;
ELSIF job='ANALYST’AND sal>=1500 AND sal<=2500 THEN
flag=TRUE;
ELSIF job='CLERK’AND sal>=1500 AND sal<=2500 THEN
flag=TRUE;
END IF;
END;

–如果薪水在此范围内,则显示消息“salaly is ok!” ,否则,更新薪水为该范围内的最小值

–编写一个函数以显示该雇员在此组织中的工作天数
CREATE OR REPLACE function f_8(NAME VARCHAR2) RETURN NUMBER
IS
num NUMBER;
BEGIN
SELECT months_between(SYSDATE,hiredate)*30 INTO num FROM emp WHERE ename=NAME;
RETURN num;
END;

DECLARE
num NUMBER;
BEGIN
num := f_8(‘SCOTT’);
DBMS_OUTPUT.put_line(round(num));
END;
/

/*
过程的参数类型:
• IN:值传递,默认的
• IN OUT:带值进,带值出
• OUT:不带值进,带值出
*/

–如果编译错误。可以用
show errors or show errors procedure myproc

–打印一个数字
CREATE OR REPLACE PROCEDURE myproc
AS
i NUMBER ;
BEGIN
i := 100 ;
DBMS_OUTPUT.put_line('i = '||i) ;
END;
/

–执行过程
exec myproc;

–可以传入部门的编号,部门的名称,部门的位置,之后调用此过程就可以完成部门的增加操作。
CREATE OR REPLACE PROCEDURE myproc(dno dept.deptno%TYPE,name dept.dname%TYPE,dl dept.loc%TYPE)
AS
cou NUMBER;
BEGIN
– 判断插入的部门编号是否存在,如果存在则不能插入
SELECT COUNT(deptno) INTO cou FROM dept WHERE deptno=dno;
IF cou=0 THEN
– 可以增加新的部门
INSERT INTO dept(deptno,dname,loc) VALUES(dno,name,dl);
DBMS_OUTPUT.put_line('部门插入成功! ') ;
ELSE
DBMS_OUTPUT.put_line('部门已存在,无法插入! ') ;
END IF ;
END ;
/

–IN OUT 类型:
CREATE OR REPLACE PROCEDURE myproc(dno IN OUT dept.deptno%TYPE,name dept.dname%TYPE,dl dept.loc%TYPE)
AS
cou NUMBER ;
BEGIN
– 判断插入的部门编号是否存在,如果存在则不能插入
SELECT COUNT(deptno) INTO cou FROM dept WHERE deptno=dno;
IF cou=0 THEN
– 可以增加新的部门
INSERT INTO dept(deptno,dname,loc) VALUES(dno,name,dl) ;
DBMS_OUTPUT.put_line('部门插入成功! ') ;
– 修改 dno 的值
dno := 1 ;
ELSE
DBMS_OUTPUT.put_line('部门已存在,无法插入! ') ;
dno := -1 ;
END IF ;
END ;
/
–编写 PL/SQL 块验证过程:
DECLARE
deptno dept.deptno%TYPE ;
BEGIN
deptno := 12 ;
myproc(deptno,‘开发’,‘南京’) ;
DBMS_OUTPUT.put_line(deptno) ;
END ;
/

–OUT 类型 不带任何值进,只把值带出来。
CREATE OR REPLACE PROCEDURE myproc(dno OUT dept.deptno%TYPE)
AS
I number
BEGIN
I:= dno;
END ;
/

–执行上面的存储过程
DECLARE
deptno dept.deptno%TYPE ;
BEGIN
deptno :=12
myproc(deptno) ;
DBMS_OUTPUT.put_line(deptno) ;
END ;
/

–下面编写一个存储过程,要求,可以传入部门的编号,部门的名称,部门的位置,之后调用此过程就可以完成部门的增加操作。
create or replace procedure myproc(dno dept.deptno%type,dn dept.dname%type,dl dept.loc%type)
as
cou number;
begin
select count(*) into cou from dept where deptno = dno;
if cou=0 then
insert into dept values (dno,dn,dl);
dbms_output.put_line(‘增加部门成功’);
else
dbms_output.put_line(‘部门已存在’);
end if;
end;
/

–创建三张表 dept10,dept20,dept30,表结构和 dept 一致(不拷贝数据,这样只有结构)
create table dept10 as select * from dept where 1=2;
create table dept20 as select * from dept where 1=2;
create table dept30 as select * from dept where 1=2;

–编写一个存储过程 mypro,
–把 dept 表中 depto=10 的数据,存到 dept10
–把 dept 表中 depto=20 的数据,存到 dept20
–把 dept 表中 depto=30 的数据,存到 dept30
–执行该存储过程

–方法一
create or replace procedure myproc
as
begin
insert into dept10 select * from dept where deptno=10;
insert into dept20 select * from dept where deptno=20;
insert into dept30 select * from dept where deptno=30;
end;
/

–方法二
create or replace procedure mypro
as
cursor mycur is select * from dept;
empInfo emp%ROWTYPE ;
begin
for empInfo in mycur loop
if empInfo.deptno = 10 then
insert into dept10 values(empInfo.deptno, empInfo.dname, empInfo.loc);
elsif empInfo.deptno = 20 then
insert into dept20 values(empInfo.deptno, empInfo.dname, empInfo.loc);
elsif empInfo.deptno = 30 then
insert into dept30 values(empInfo.deptno, empInfo.dname, empInfo.loc);
end if;
end loop;
end;
/

exec myproc;

–删除 mypro 存储过程
drop procedure myproc;

–写一个存储过程 (给一个用户名,判断该用户名是否存在)
create or replace procedure findName(name emp.ename%type,en out number)
as i number;
begin
select count(*) into i from emp where ename=name;
if i=1 then
en:=i;
dbms_output.put_line(‘用户存在’);
else
en:=0;
dbms_output.put_line(‘用户不存在’);
end if;
end;
/

–执行该存储过程
DECLARE
deptno dept.deptno%TYPE ;
BEGIN
findName(upper(‘aaa’),deptno) ;
DBMS_OUTPUT.put_line(deptno) ;
END ;
/

–编写一个存储过程,批量插入 1000 条数据(只插入 ID 为奇数的数据)
create table test(i number(10));

create or replace procedure add1
as
i number(10);
begin
for i in 1…1000 loop
if mod(i,2) = 1 then
insert into test values(i);
end if;
end loop;
end;
/

PL/SQL--------------------------------------------------------------------------
Procedural Language/Structured Query Language,过程化SQL语言它是一门编程语言
它是Oracle数据库对标准SQL语句的扩展,在普通SQL语句的使用上加入了编程语言的特点,支持计算和程序控制
PL/SQL程序基本单位是程序块,通常称为PL/SQL块
PL/SQL块由三部分组成:声明部分(可选),执行部分(必有),异常处理部分(可选)

–PL/SQL块的形式如下:
declare --声明部分以declare开头,该部分主要进行变量的声明

i number(6) := 13;--声明变量并初始化
i number(6) default 13;--和上面的效果一样
str nvarchar2(10);
t date;

begin --执行部分开头。执行部分以begin开关,该部分执行一些PL/SQL语句,DQL、DML和TCL语句可以直接嵌入PL/SQL块中,即写在该部分里面
if(i=3) then
delete from student where sno=2000;
else
update student set sname=‘abc’ where sno=3000;
end if;

exception --异常处理部分以exception开头,该部分主要负责处理执行部分出现的一些异常
end;–执行部分结尾

begin–执行部分开头
dbms_output.put_line(‘Hello,World…’);–输出Hello,World
end;–执行部分结尾

declare
i number(6);
j number(6):=123; – 声明变量并初始化
k number(6) default 456; – 和上面效果一样
str nvarchar2(20);
t date;
name student.sname%TYPE; --用student表中的sname字段的类型声明变量name
stu_info student%ROWTYPE; --stu_info变量用来存放student表中的一条记录,相当于一个结构体变量
begin
i:=100;–赋值
i:=&请输入i的值; – 通过&运算符输入变量的值,其后面的内容为输入提示文本
dbms_output.put_line(‘i=’||i);

str:=&请输入一个字符串;
dbms_output.put_line('str='||str);select sno into j from student where sname='关云长';
dbms_output.put_line('关云长的学号为:'||j);select sno,phone into j,str from student where sname='刘玄德';
dbms_output.put_line('刘玄德的学号为:'||j||'  手机号为:'||str);  i:=&请输入一个学号;
select sname into name from student where sno=i;
dbms_output.put_line('学号为'||i||'的学生姓名是'||name);
dbms_output.put_line('test');

exception
when no_data_found then
dbms_output.put_line(‘学号’||i||‘无效!’);
when too_many_rows then
dbms_output.put_line(‘找到多条记录!’);
when others then
dbms_output.put_line(‘未知错误’);
end;

–数据类型----------------------------------------------------------------------
Oracle内置数据类型(number,char,nvarchar2,date等)
列类型(%TYPE)
行类型(%ROWTYPE)
游标(CURSOR)

–游标(Cursor)-----------------------------------------------------
–作用:将从数据库中查询的数据以临时表的形式存放在内存中,通过游标可以操作这些数据,比如返回一条或者多条数据,也可以进行DML操作
–游标的分类:显式游标、隐式游标
–游标的使用:–
–显示游标:声明游标,打开游标,提取数据,关闭游标
–隐式游标:由Oracle系统自动负责声明、打开和关闭,无需我们显示进行,我们只需要提取数据就行
–显示游标主要用于处理多行记录,游标变量需要我们自己定义;
–隐式游标主要用于处理selcect into和DML操作,其名字固定为SQL

–游标常用的四个属性:
–%FOUND,%NOTFOUND,%ISOPEN,%ROWCOUNT

declare
CURSOR mycur is select * from student;
stu student%ROWTYPE;
begin
/*
open mycur;–打开游标
fetch mycur into stu;
while(mycur%FOUND) loop
dbms_output.put_line(stu.sno||’ '||stu.sname);
fetch mycur into stu;
end loop;

close mycur;--关闭游标

*/

/*
open mycur;
fetch mycur into stu;
loop
dbms_output.put_line(stu.sno||’ '||stu.sname);
fetch mycur into stu;
exit when (mycur%notfound);
end loop;
close mycur;
*/

--游标for循环,不需要显式打开、关闭和遍历游标
--while,do...while循环必须自己显式打开、关闭和遍历游标
--for开始之前游标并没有打开,当执行for循环时游标被自动打开
for stu in mycur loop
dbms_output.put_line(mycur%ROWCOUNT||' '||stu.sno||' '||stu.sname);
end loop;
--for循环结束后游标自动关闭,所以下面的输出没有执行
if mycur%ISOPEN thendbms_output.put_line('cursor open!');close mycur;
end if;

end;

–隐式游标
begin
update student set sname=‘黄忠’ where sno =1027;

if(SQL%NOTFOUND) then
dbms_output.put_line('没有记录被更新!');
else
dbms_output.put_line(SQL%ROWCOUNT||'条记录被更新!');
end if;

end;

–通过游标进行DML操作
declare
cursor mycur is select * from sc for update;
abc sc%rowtype;
begin
for abc in mycur loop–abc处可为任意标识符
update sc set score=score+1 where current of mycur;
end loop;
end;

set serveroutput on
–查询雇员编号为 7369 的信息(肯定是一行信息)。
DECLARE
eno emp.empno%TYPE ;
empInfo emp%ROWTYPE ;
BEGIN
eno := &en ;
SELECT * INTO empInfo FROM emp WHERE empno=eno ;
DBMS_OUTPUT.put_line('雇员编号: '||empInfo.empno) ;
DBMS_OUTPUT.put_line('雇员姓名: '||empInfo.ename) ;
END ;
/

set serveroutput on
–使用 for 循环操作游标(比较常用)
DECLARE
– 声明游标
CURSOR mycur IS SELECT * FROM emp where empno=-1;
empInfo emp%ROWTYPE ;
cou NUMBER ;
BEGIN
– 游标操作使用循环,但是在操作之前必须先将游标打开
FOR empInfo IN mycur LOOP
cou := mycur%ROWCOUNT ;
DBMS_OUTPUT.put_line(cou||'雇员编号: '||empInfo.empno) ;
DBMS_OUTPUT.put_line(cou||'雇员姓名: '||empInfo.ename) ;
END LOOP ;
END ;
/

set serveroutput on
–编写第一个游标,输出全部的信息。
DECLARE
– 声明游标
CURSOR mycur IS SELECT * FROM emp ; – List (EmpPo)
empInfo emp%ROWTYPE ;
BEGIN
– 游标操作使用循环,但是在操作之前必须先将游标打开
OPEN mycur ;
– 使游标向下一行
FETCH mycur INTO empInfo ;
– 判断此行是否有数据被发现
WHILE (mycur%FOUND) LOOP
DBMS_OUTPUT.put_line('雇员编号: '||empInfo.empno) ;
DBMS_OUTPUT.put_line('雇员姓名: '||empInfo.ename) ;
– 修改游标,继续向下
FETCH mycur INTO empInfo ;
END LOOP ;
END ;
/

set serveroutput on
–也可以使用另外一种方式循环游标: LOOP…END LOOP;
DECLARE
– 声明游标
CURSOR mycur IS SELECT * FROM emp ;
empInfo emp%ROWTYPE ;
BEGIN
– 游标操作使用循环,但是在操作之前必须先将游标打开
OPEN mycur ;
LOOP
– 使游标向下一行
FETCH mycur INTO empInfo ;
EXIT WHEN mycur%NOTFOUND ;
DBMS_OUTPUT.put_line('雇员编号: '||empInfo.empno) ;
DBMS_OUTPUT.put_line('雇员姓名: '||empInfo.ename) ;
END LOOP ;
END ;
/

set serveroutput on
–可以使用 ROWCOUNT 对游标所操作的行数进行记录。
DECLARE
– 声明游标
CURSOR mycur IS SELECT * FROM emp ;
empInfo emp%ROWTYPE ;
cou NUMBER ;
BEGIN
–在打开游标之前最好先判断游标是否已经是打开的。
–通过 ISOPEN 判断,格式:游标%ISOPEN
– 游标操作使用循环,但是在操作之前必须先将游标打开
IF mycur%ISOPEN THEN
null ;
ELSE
OPEN mycur ;
END IF ;
LOOP
– 使游标向下一行
FETCH mycur INTO empInfo ;
EXIT WHEN mycur%NOTFOUND ;
cou := mycur%ROWCOUNT ;
DBMS_OUTPUT.put_line(cou||'雇员编号: '||empInfo.empno) ;
DBMS_OUTPUT.put_line(cou||'雇员姓名: '||empInfo.ename) ;
END LOOP ;
END ;
/

set serveroutput on
/一次性上涨全部雇员的工资。根据它所在的部门涨工资,规则:
• 10 部门上涨 10%
• 20 部门上涨 20%
• 30 部门上涨 30%
所有部门的上涨工资,最不能超过 5000,如果超过 5000,则工资就为 5000。
/
declare
cursor mycur is select * from emp;
empInfo emp%rowtype;
s emp.sal%type;
begin
for empInfo in mycur loop
if empInfo.deptno = 10 then
s := empInfo.sal1.1;
elsif empInfo.deptno = 20 then
s := empInfo.sal
1.2;
elsif empInfo.deptno = 30 then
s := empInfo.sal* 1.3;
end if;
if s > 5000 then
s := 5000;
end if;
update emp set sal = s where empno = empInfo.empno;
end loop;
end;
/

set serveroutput on
declare
type cur is ref cursor return emp%rowtype;–声明游标类型
cur_dept cur;–声明游标变量
dept_record emp%rowtype;–声明记录变量
begin
if not cur_dept%isopen then
open cur_dept for select * from emp;–打开游标变量,指定查询语句
end if;
fetch cur_dept into dept_record;–提取数据到记录变量中

--通过循环处理所有的数据行
while (cur_dept%found or cur_dept%found is null) loopdbms_output.put_line(dept_record.empno || ' ' || dept_record.ename);fetch cur_dept into dept_record;--提取数据到记录变量中
end loop;
dbms_output.put_line('记录的总行数:' || cur_dept%rowcount);
close cur_dept;--关闭游标

end;
/

–流程控制结构------------------------------------------------------------------
declare
i number:=1;
–sum是关键字,不能用作变量名,否则报错
sum1 number:=0;
begin

/*
–条件选择结构
i:=&年份;
if(i mod 4=0 and i mod 100<>0 or i mod 400=0) then
dbms_output.put_line(i||‘是闰年!’);
–elsif …then
else
dbms_output.put_line(i||‘不是闰年!’);
end if;
*/

/*
–case条件语句
i:=&操作代号;
–多分支条件选择结构
case i
when 1 then
dbms_output.put_line(‘关机’);
when 2 then
dbms_output.put_line(‘重启’);
when 3 then
dbms_output.put_line(‘注销’);
else
dbms_output.put_line(‘错误’);
end case;
*/

/*
–while循环
while(i<=100) loop
sum1:=sum1+i;
i:=i+1;
end loop;
dbms_output.put_line(sum1);
*/

   --do-while循环loopsum1:=sum1+i;i:=i+1;exit when i>100;end loop;dbms_output.put_line(sum1);

/*
–for循环
for i in 1…100 loop
sum1:=sum1+i;
end loop;

   dbms_output.put_line(sum1);

*/
end;

chr(10) --换行
char(13) --回车

set serveroutput on
DECLARE
i NUMBER ;
BEGIN
i := 30 ;
DBMS_OUTPUT.put_line('I 的内容为: '||i) ;
END ;

set serveroutput on
DECLARE
i NUMBER ;
BEGIN
i:= 1/0;
EXCEPTION
when ZERO_DIVIDE then
dbms_output.put_line(‘error’);
END ;

–自己输入参数值
set serveroutput on
DECLARE
eno NUMBER ;
en VARCHAR2(30) ;
BEGIN
– 输入的信息保存在 eno 里
eno := &no ;
– 之后根据 eno 的值,对数据库进行查询操作
SELECT ename INTO en FROM emp WHERE empno=eno ;
DBMS_OUTPUT.put_line('编号为: '||eno||'雇员的姓名为: '||en) ;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.put_line('没有此雇员 ') ;
END ;
/

set serveroutput on
–在以上的查询中再进一步:可以根据雇员的编号查出姓名及其领导的姓名和所在的部门,进行显示。
declare
eno emp.empno%type;–表示以 emp 表中的 empno 字段的类型定义变量
en emp.ename%type;
mn emp.ename%type;
–dept dept%rowtype;–表示 dept 是一行数据,类似于 Hibernate 的 PO
begin
eno := &no;-- 输入的信息保存在 eno 里
– 之后根据 eno 的值,对数据库进行查询操作
–e.ename,m.ename,d.dname INTO en,mn,dn:一次可以同时放进去多个值
select e.ename,m.ename into en,mn from emp e,emp m where e.empno = eno and e.mgr = m.empno;
dbms_output.put_line('编号为: '||eno||'雇员的姓名为: '||en);
dbms_output.put_line('编号为: '||eno||'雇员的上级姓名为: '||mn) ;
–DBMS_OUTPUT.put_line(dept.deptno) ;
EXCEPTION
WHEN no_data_found
THEN DBMS_OUTPUT.put_line('没有此雇员 ') ;
END ;
/

–此循环是先执行一次之后再进行判断
–循环输出 1~10。
DECLARE
cou NUMBER ;
BEGIN
– 必须给一个初始值
cou := 1 ;
LOOP
DBMS_OUTPUT.put_line('cou = '||cou) ;
EXIT WHEN cou>10 ;
cou := cou + 1 ;
END LOOP ;
END ;
/

–此语句,是先判断,之后如果条件满足则执行,与 while 循环类似。
DECLARE
cou NUMBER ;
BEGIN
– 必须给一个初始值
cou := 1 ;
WHILE(cou<10)
LOOP
DBMS_OUTPUT.put_line('cou = '||cou) ;
cou := cou + 1 ;
END LOOP ;
END ;
/

DECLARE
cou NUMBER ;
BEGIN
FOR cou IN 1…10
LOOP
DBMS_OUTPUT.put_line('cou = '||cou) ;
END LOOP ;
END ;
/

DECLARE
cou NUMBER ;
BEGIN
cou := 11 ;
IF cou>10
THEN DBMS_OUTPUT.put_line('cou = '||cou) ;
END IF ;
END ;
/

DECLARE
cou NUMBER ;
BEGIN
cou := 1 ;
IF cou>10
THEN
DBMS_OUTPUT.put_line('cou = '||cou) ;
ELSE
DBMS_OUTPUT.put_line(‘条件不满足’) ;
END IF ;
END ;
/

set serveroutput on
DECLARE
cou NUMBER ;
BEGIN
cou := 1 ;
IF cou>10
THEN DBMS_OUTPUT.put_line('cou = '||cou) ;
ELSIF cou<5
THEN DBMS_OUTPUT.put_line(‘值小于 5’) ;
ELSE
DBMS_OUTPUT.put_line(‘条件不满足’) ;
END IF ;
END ;
/

set serveroutput on
DECLARE
eno emp.empno%TYPE ;
sal emp.sal%TYPE ;
BEGIN
eno := &en ;
SELECT sal INTO sal FROM emp WHERE empno=eno ;
IF sal>3500 THEN
goto po1 ;
ELSIF sal>2000 THEN
goto po2 ;
ELSE
goto po3 ;
END IF ;
<> DBMS_OUTPUT.put_line('高工资。。。 ') ;
<> DBMS_OUTPUT.put_line('中等工资。。 ') ;
<> DBMS_OUTPUT.put_line('低工资。。。 ') ;
END ;
/

–输入一个雇员的编号,如果其工资高于 3500,则显示高工资,工资大于 2000,则显示中等工资,工资小于 2000 的则认为是低等工资。
set serveroutput on
DECLARE
eno emp.empno%TYPE ;
sal emp.sal%TYPE ;
BEGIN
eno := &en ;
SELECT sal INTO sal FROM emp WHERE empno=eno ;
IF sal>3500 THEN
DBMS_OUTPUT.put_line('高工资。。。 ') ;
ELSIF sal>2000 THEN
DBMS_OUTPUT.put_line('中等工资。。 ') ;
ELSE
DBMS_OUTPUT.put_line('底工资。。。 ') ;
END IF ;
END ;
/

/*
输入一个雇员编号,根据它所在的部门涨工资,规则:
• 10 部门上涨 10%
• 20 部门上涨 20%
• 30 部门上涨 30%
所有部门的上涨工资,最不能超过 5000,如果超过 5000,则工资就为 5000。
/
DECLARE
eno emp.empno%TYPE ;
dno emp.deptno%TYPE ;
sal emp.sal%TYPE ;
BEGIN
eno := &en ;
SELECT deptno,sal INTO dno,sal FROM emp WHERE empno=eno ;
IF dno=10 THEN
IF sal
1.1>5000 THEN
UPDATE emp SET sal=5000 WHERE empno=eno ;
ELSE
UPDATE emp SET sal=sal1.1 WHERE empno=eno ;
END IF ;
ELSIF dno=20 THEN
IF sal
1.2>5000 THEN
UPDATE emp SET sal=5000 WHERE empno=eno ;
ELSE
UPDATE emp SET sal=sal1.2 WHERE empno=eno ;
END IF ;
ELSIF dno=30 THEN
IF sal
1.3>5000 THEN
UPDATE emp SET sal=5000 WHERE empno=eno ;
ELSE
UPDATE emp SET sal=sal*1.3 WHERE empno=eno ;
END IF ;
ELSE
null ;
END IF ;
END ;
/

declare
eno emp.empno%TYPE;
dno emp.deptno%TYPE;
esal emp.sal%TYPE;
begin
eno:=&no;
select deptno,sal into dno,esal from emp where empno=eno;
if dno=10 then
esal := esal + esal0.1;
elsif dno=20 then
esal := esal + esal
0.2;
elsif dno=30 then
esal := esal + esal*0.3;
end if;
if esal>5000 then
esal:=5000;
end if;
update emp set sal=esal where empno=eno;
end;
/

–接收部门编号,显示部门名和地理位置
declare
sno dept.deptno%type;
dname dept.dname%type;
loc dept.loc%type;
begin
sno:=&no;
select dname,loc into dname,loc from dept where deptno=sno;
dbms_output.put_line(dname||’ '||loc);
exception
when no_data_found then
dbms_output.put_line(‘not find data’);
end;
/

–接收雇员号,显示该雇员的工资和提成,没有提成的用 0 替代。(用%type 实现)
declare
sno emp.empno%type;
sal emp.sal%type;
comm emp.comm%type;
begin
sno:=&no;
select sal,nvl(comm,0) into sal,comm from emp where empno=sno;
dbms_output.put_line(sal||’ '||comm);
exception
when no_data_found then
dbms_output.put_line(‘not find data’);
end;
/

–接收雇员号,显示 该雇员的所有信息,没有提成的用 0 替代。(用%rowtype 实现)
declare
sno emp.empno%type;
e1 emp%rowtype;
begin
sno:=&no;
select * into e1 from emp where empno=sno;
dbms_output.put_line(e1.empno||’ ‘||e1.ename||’ ‘||e1.job||’ ‘||e1.mgr||’ ‘||e1.hiredate||’ ‘||e1.sal||’ ‘||nvl(e1.comm,0)||’ '||e1.deptno);
exception
when no_data_found then
dbms_output.put_line(‘not find date’);
end;
/

–接收一个雇员名,判断他的 job,根据 job 不同,为他增加相应的 sal(用 if-elsif实现)
declare
sno emp.empno%type;
sname emp.ename%type;
ejob emp.job%type;
esal emp.sal%type;
begin
– sno := &no;
sname:=&sn;
select job,sal into ejob,esal from emp where ename = sname;
if(ejob=‘ANALYST’) then
esal:=esal+esal0.1;
elsif(ejob=‘CLERK’) then
esal:=esal+esal
0.2;
elsif(ejob=‘MANAGER’) then
esal:=esal+esal0.2;
elsif(ejob=‘PRESIDENT’) then
esal:=esal+esal
0.2;
elsif(ejob=‘SALESMAN’) then
esal:=esal+esal*0.2;
end if;
update emp set sal=esal;
exception
WHEN NO_data_found then
dbms_output.put_line(‘not find data’);
end;
/

–用 loop 循环结构,为 dept 表增加 50-90 这些部门
declare
no number;
begin
no :=50;
while (no <= 90) loop
insert into dept(deptno) values(no);
no := no+10;
end loop;
end;
/

set serveroutput on
–接收一个雇员名,显示该雇员的所有内容,(用%rowtype 实现),当没有这个雇员时( no_data_found),用异常来显示错误提示
declare
name emp.ename%type;
e1 emp%rowtype;
begin
name:=&name;
select * into e1 from emp where ename=name;
dbms_output.put_line(e1.empno||’ ‘||e1.job||’ ‘||e1.mgr||’ ‘||e1.hiredate||’ ‘||e1.sal||’ ‘||e1.comm||’ '||e1.deptno);
exception
when no_data_found then
dbms_output.put_line('没有这个雇员 ');
end;
/

set serveroutput on
–编写一个 PL/SQL 程序块以计算某个雇员的年度薪水总额
declare
name emp.ename%type;
sal number;
begin
name := &name;
select (sal*12) into sal from emp where ename = name;
dbms_output.put_line(‘薪水’||sal);
exception
when no_data_found then
dbms_output.put_line('没有这个雇员 ');
end;
/

set serveroutput on
–编写一个 PL/SQL 程序块以向 emp 表添加 10 新雇员编号( 7901-7910)
declare
eno emp.empno%type;
begin
eno := 7911;
loop
insert into emp(empno) values(eno);
exit when eno = 7920;
eno := eno+1;
end loop;
end;
/

set serveroutput on
–接受 2 个数相除,并显示结果,如果除数为 0,则显示错误提示;
declare
a number;
b number;
begin
a := &a;
b := &b;
dbms_output.put_line(a||‘除以’||b||’=’||a/b);
exception
when zero_divide then
dbms_output.put_line('被除数不能为 0! ');
end;
/

事务(Transaction)-----------------------------------------------------------------
一系列连续的数据库操作,具有ACID四大特性

特点:
每个连接都会产生一个新的事务
执行commit语句会提交当前事务,并创建一个新的事务
当执行DDL或DCL语句时,系统会自动提交当前事务,并创建一个新的事务
当断开数据库连接时,系统会自动提交当前事务
在一个事务提交之前,其他用户是看不到该事务所带来的各种改变的,并且可以回滚到之前的状态
在事务提交后,其他用户可以看到事务的操作,此时不能再回滚到该事务之前的状态

操作:
commit 提交当前事务
rollback 回滚事务
savepoint 保存当前状态

select * from person;
insert into person values(1004,‘魏文长’,‘1’,‘7531265478’);
commit;–若不使用commit则不能实时的改变数据库数据

create index person_name_index on Person(name);

–设置事务回滚时间截点
savepoint d1;
delete from person where id=1003;
savepoint d2;
update person set phone=‘4764644’ where id=1001;–这里省略很多DML语句

rollback;

rollback to d2;
rollback to d1;

–Oracle技巧,高级用法--------------------------------------------------------------------
–设置字段长度
select cast(’ ’ as varchar(5)) as a from dual;

–查询’SES_ADDR’这个字段在哪张表中出现
select table_name,owner from dba_tab_cols where column_name = ‘SES_ADDR’;

–查询某用户下所有表
select table_name from all_tables where owner=‘SCOTT’;

–查询 EMP 表中所有字段(列)
select * from all_tab_columns where table_name=‘EMP’;

–列出表的索引列
select * from sys.all_ind_columns where table_name=‘EMP’;
select * from sys.all_ind_columns where upper(table_name)=‘CAREUSERHAM’;

–列出表中约束
select * from all_constraints where table_name=‘EMP’;

–在 oracle 中描述数据字典视图
select table_name ,comments from dictionary where table_name like ‘%TABLE%’;

–处理锁表情况
用SELECT OB.OBJECT_NAME, LK.SID, VS.TERMINAL FROM VLOCKLK,USEROBJECTSOB,VLOCK LK,USER_OBJECTS OB, VLOCKLK,USERO​BJECTSOB,VSESSION VS WHERE LK.ID1 = OB.OBJECT_ID AND LK.SID = VS.SID AND OB.OBJECT_TYPE = ‘TABLE’。–查到被锁记录的SID,点击工具->会话;选中要删除的SID那一行数据,点击【关掉】

–SQL优化-----------------------------------------------------------------------
–尽量少用 IN 操作符
–基本上所有的 IN 操作符都可以用 EXISTS 代替, 在选择 IN 或 EXIST 操作时,要根据主子表数据量大小来具体考虑

–尽量用 NOT EXISTS 或者外连接替代 NOT IN 操作符
–因为 NOT IN 不能应用表的索引

–尽量不用“<>”或者“!=”操作符
–不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 比如: a<>0改为 a>0 or a<0

–在设计表时, 把索引列设置为 NOT NULL
–判断字段是否为空一般是不会应用索引的,因为 B 树索引是不索引空值的。

–尽量不用通配符“%”或者“”作为查询字符串的第一个字符
–当通配符“%”或者“
”作为查询字符串的第一个字符时,索引不会被使用。比如用 T 表中Column1 LIKE „%5400%‟ 这个条件会产生全表扫描,如果改成 Column1 ‟X5400%‟ ORColumn1 LIKE ‟B5400%‟ 则会利用 Column1 的索引进行两个范围的查询,性能肯定大大提高。

–Where 子句中避免在索引列上使用计算
–如果索引不是基于函数的,那么当在 Where 子句中对索引列使用函数时,索引不再起作用。因此 Where 子句中避免在索引列上使用计算。
–比如: substr(no,1,4)=‟5400‟,优化处理: no like „5400%‟trunc(hiredate)=trunc(sysdate) , 优 化 处 理 : hiredate >=trunc(sysdate) and hiredate<trunc(sysdate+1)

–用“>=”替代“>”

–WHERE 后面的条件顺序要求
–WHERE 后面的条件, 表连接语句写在最前, 可以过滤掉最大数量记录的条件居后。
–比如:
Select * from zl_yhjbqk where dy_dj = ‘1KV 以下’ and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = ‘1KV 以下’

–他会优先查询左边的,若是左边的条件符合的比较多,建议让少的写在左边

–进行了显式或隐式的运算的字段不能进行索引
–比如:
/*
就是不能有计算过程的
ss_df+20>50,优化处理: ss_df>30
„X‟||hbs_bh>‟X5400021452‟,优化处理: hbs_bh>‟5400021542‟
sk_rq+5=sysdate,优化处理: sk_rq=sysdate-5
hbs_bh=5401002554,优化处理: hbs_bh=‟ 5401002554‟,注:此条件对 hbs_bh 进行隐式的 to_number 转换,因为 hbs_bh 字段是字符型。
*/

–用 UNION ALL 代替 UNION

–由根找到父子树结构
SELECT EMPNO,ENAME,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR START WITH ENAME=‘KING’ ORDER BY EMPNO;
–查找由FORD和BLAKE 领导的所有雇员的信息。
SELECT EMPNO,ENAME,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR START WITH ENAME IN (‘FORD’,‘BLAKE’);
–LEVEL使用必须存在 CONNECT BY
SELECT LEVEL,EMPNO,ENAME,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR START WITH ENAME=‘KING’;
–设置该字段显示的列宽长度(放在命令窗口运行)
COLUMN EMPLOYEE FORMAT A100
SELECT EMPNO,RPAD(’ ‘,LEVEL3) || ENAME EMPLOYEE,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR START WITH ENAME=‘KING’;
–除去scott的所有节点
SELECT EMPNO,RPAD(’ ',LEVEL
3) ||ENAME EMPLOYEE,MGR FROM EMP WHERE ENAME!=‘SCOTT’ CONNECT BY PRIOR EMPNO=MGR START WITH ENAME=‘KING’;
–显示KING领导全体雇员信息,除去雇员SCOTT,以及BLAKE领导的一支。
SELECT EMPNO,RPAD(’ ',LEVEL3) || ENAME EMPLOYEE,MGR FROM EMP WHERE ENAME!=‘SCOTT’ CONNECT BY PRIOR EMPNO=MGR AND ENAME!=‘BLAKE’ START WITH ENAME=‘KING’;
–显示KING领导下的全体雇员信息,除去SCOTT领导的一支。
SELECT EMPNO,RPAD(’ ',LEVEL
3) ||ENAME EMPLOYEE,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR AND ENAME!=‘SCOTT’ START WITH ENAME=‘KING’;

–由子上溯找到父子树结构
–从SMITH节点开始自底向上查找EMP的树结构。
SELECT EMPNO,ENAME,MGR FROM EMP CONNECT BY EMPNO=PRIOR MGR START WITH ENAME=‘MILLER’;
SELECT EMPNO,ENAME,MGR FROM EMP CONNECT BY PRIOR MGR=EMPNO START WITH ENAME=‘MILLER’;
–查找JONES直接或间接领导的所有雇员信息。
SELECT EMPNO,ENAME,MGR FROM EMP CONNECT BY PRIOR EMPNO=MGR START WITH ENAME=‘JONES’;


–固定的列转行
create table test_gd
(
student nvarchar2(36),
subject nvarchar2(36),
grade nvarchar2(36)
);

insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student1’, ‘语文’, ‘80’);
insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student1’, ‘数学’, ‘70’);
insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student1’, ‘英语’, ‘60’);
insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student2’, ‘语文’, ‘90’);
insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student2’, ‘数学’, ‘80’);
insert into test_gd (STUDENT, SUBJECT, GRADE) values (‘student2’, ‘英语’, ‘100’);
–sum
select student,sum(decode(subject,‘语文’, grade,null)) 语文,sum(decode(subject,‘数学’, grade,null)) 数学,sum(decode(subject,‘英语’, grade,null)) 英语 from test_gd group by student;

CREATE TABLE t_col_row
(
ID INT,
c1 VARCHAR2(10),
c2 VARCHAR2(10),
c3 VARCHAR2(10)
);

INSERT INTO t_col_row VALUES (1, ‘v11’, ‘v21’, ‘v31’);
INSERT INTO t_col_row VALUES (2, ‘v12’, ‘v22’, NULL);
INSERT INTO t_col_row VALUES (3, ‘v13’, NULL, ‘v33’);
INSERT INTO t_col_row VALUES (4, NULL, ‘v24’, ‘v34’);
INSERT INTO t_col_row VALUES (5, ‘v15’, NULL, NULL);
INSERT INTO t_col_row VALUES (6, NULL, NULL, ‘v35’);
INSERT INTO t_col_row VALUES (7, NULL, NULL, NULL);

–union all 是显示全部
–union 是自动压缩重复的数据
–若是想显示全部,就去掉对where的判断
SELECT id, ‘c1’ cn, c1 cv FROM t_col_row WHERE c1 IS NOT NULL UNION ALL SELECT id, ‘c2’ cn, c2 cv FROM t_col_row WHERE c2 IS NOT NULL UNION ALL SELECT id, ‘c3’ cn, c3 cv FROM t_col_row WHERE c3 IS NOT NULL;

–MODEL
SELECT id, cn, cv FROM t_col_row MODEL RETURN UPDATED ROWS PARTITION BY (ID) DIMENSION BY (0 AS n) MEASURES (‘xx’ AS cn,‘yyy’ AS cv,c1,c2,c3) RULES UPSERT ALL (cn[1] = ‘c1’,cn[2] = ‘c2’,cn[3] = ‘c3’,cv[1] = c1[0],cv[2] = c2[0],cv[3] = c3[0]) ORDER BY ID,cn;

–collection
–要创建一个对象和一个集合:
CREATE TYPE cv_pair AS OBJECT(cn VARCHAR2(10),cv VARCHAR2(10));
CREATE TYPE cv_varr AS VARRAY(8) OF cv_pair;
SELECT id, t.cn AS cn, t.cv AS cv FROM t_col_row,TABLE(cv_varr(cv_pair(‘c1’, t_col_row.c1),cv_pair(‘c2’, t_col_row.c2),cv_pair(‘c3’, t_col_row.c3))) t ORDER BY 1,2;

–不固定的列转行----------------------------------------------------------------
create table test_bgd
(
c1 nvarchar2(36),
c2 nvarchar2(36)
);
insert into test_bgd (C1, C2) values (‘1’, ‘我’);
insert into test_bgd (C1, C2) values (‘1’, ‘是’);
insert into test_bgd (C1, C2) values (‘1’, ‘谁’);
insert into test_bgd (C1, C2) values (‘2’, ‘知’);
insert into test_bgd (C1, C2) values (‘2’, ‘道’);
insert into test_bgd (C1, C2) values (‘3’, ‘不’);

–创建函数
CREATE OR REPLACE FUNCTION get_c2(tmp_c1 NUMBER)
RETURN VARCHAR2
IS
Col_c2 VARCHAR2(4000);
BEGIN
FOR cur IN (SELECT c2 FROM test_bgd WHERE c1 = tmp_c1) LOOP
Col_c2 := Col_c2 || cur.c2;
END LOOP;
Col_c2 := rtrim(Col_c2,1);
RETURN Col_c2;
END;
/

–得出结果
select distinct c1 ,get_c2(c1) cc2 from test_bgd order by c1;

–LAG是将这一行的数据向下移动后成为新一行的数据,LEAD则是向上移动
–PARTITION BY 是按照某一个字段分区
SELECT c1,SUBSTR(MAX(SYS_CONNECT_BY_PATH(c2, ‘;’)),2) NAME FROM
(
SELECT c1,c2,rn,LAG (rn) OVER (PARTITION BY c1 ORDER BY rn) rn1 from (SELECT c1, c2, ROW_NUMBER () OVER (ORDER BY c1) rn FROM test_bgd) a
)
START WITH rn1 IS NULL CONNECT BY rn1 = PRIOR rn GROUP BY c1 order by c1

–数据库备份及恢复--------------------------------------------------------------
Expdp------------------------
一、创建逻辑目录,该命令不会在操作系统创建真正的目录,而是将该目录写入Oracle的数据字典中,最好以system等管理员创建。
create directory dpdata1 as ‘d:\test\dump’;

创建逻辑目录:使用数据泵之前,需要创建一个存放文件的目录。这个目录要写入Oracle的数据字典中才能识别。并且需要为数据库用户授予使用DIRECTORY对象权限.
先在系统中手工建立要存放备份文件的目录,如 D:\oracle\bac。

二、查看管理理员目录(同时查看操作系统是否存在,因为Oracle并不关心该目录是否存在,如果不存在,则出错)
其中,第一行数据为刚刚在D盘创建的bac目录,第8行为系统默认的保存目录。 如果不创建逻辑目录,则可以使用系统提供的默认目录,
select * from dba_directories;

三、给scott用户赋予在指定目录的操作权限,最好以system等管理员赋予。
grant read,write on directory dpdata1 to scott;

四、导出数据
1)按用户导
expdp scott/tiger@orcl schemas=scott dumpfile=expdp.dmp DIRECTORY=dpdata1;
2)并行进程parallel
expdp scott/tiger@orcl directory=dpdata1 dumpfile=scott3.dmp parallel=40 job_name=scott3
3)按表名导
expdp scott/tiger@orcl TABLES=emp,dept dumpfile=expdp.dmp DIRECTORY=dpdata1;
4)按查询条件导
expdp scott/tiger@orcl directory=dpdata1 dumpfile=expdp.dmp Tables=emp query=‘WHERE deptno=20’;
5)按表空间导
expdp system/manager DIRECTORY=dpdata1 DUMPFILE=tablespace.dmp TABLESPACES=temp,example;
6)导整个数据库
在手工创建的目录中可以看到生成的转存储文件和导出日志文件:日志生成在A步骤设置的目录 'D:\oracle\bac\’下
expdp system/manager DIRECTORY=dpdata1 DUMPFILE=full.dmp FULL=y logfile=expdp_test1.log;

expdp PDM503/123@ORCLLOCAL directory=DPDATA1 schemas=PDM503 dumpfile=MATTER.dmp excLUDE=TABLE:“IN (‘PDM_VOLUME_MATTER’,‘PDM_VOLUME_MATTER_HISTORY’)”

五、还原数据
Impdb---------------------------------
–先手工建立目录,并且用命令进行声明
1)导到指定用户下
impdp scott/tiger DIRECTORY=dpdata1 DUMPFILE=expdp.dmp SCHEMAS=scott;
2)改变表的owner
impdp system/manager DIRECTORY=dpdata1 DUMPFILE=expdp.dmp TABLES=scott.dept REMAP_SCHEMA=scott:system;
3)导入表空间
impdp system/manager DIRECTORY=dpdata1 DUMPFILE=tablespace.dmp TABLESPACES=example;
4)导入数据库
impdb system/manager DIRECTORY=dump_dir DUMPFILE=full.dmp FULL=y;
5)追加数据
impdp system/manager DIRECTORY=dpdata1 DUMPFILE=expdp.dmp SCHEMAS=system TABLE_EXISTS_ACTION=append;

–在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法:
–1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中
–在记录多时是个噩梦,需三五百条的分批提交,否则客户端会死掉,而且导入过程很慢。
–如果要不产生REDO 来提高 insert into 的性能,就要这样做:alter table B nologging;
–2. 建立数据库间的 dblink,然后用 create table B as select * from A@dblink where …,或 insert into B select * from A@dblink where …
–3. exp A 表,再 imp 到 B 表, exp 时可加查询条件
–4. 程序实现 select from A …,然后 insert into B …,也要分批提交
–5. 再就是 Sql Loader(sqlldr) 来导入数据,效果比起逐条 insert 来很明显

/*
sql loader 的用法:

  1. 只使用一个控制文件,在这个控制文件中包含数据(推荐)
  2. 使用一个控制文件(作为模板) 和一个数据文件
    */
    Csv 文件如下: (dept1.csv)
    " ",“DEPTNO”,“DNAME”,“LOC”
    “1”,“10”,“ACCOUNTING”,“NEW YORK”
    “2”,“20”,“RESEARCH”,“DALLAS”
    “3”,“30”,“SALES”,“CHICAGO”
    “4”,“40”,“OPERATIONS”,“BOSTON”
    “5”,“50”,“sdsaf”,“adf”
    “6”,“12”,“aaa”,“aaa”
    Ctl 文件如下: (dept1.ctl)

方式一:
Load data Infile c:\dept1.csv truncate Into table dept1
(Deptno position(1:2),
Dname position(3:5),
Loc position(6:8)
)

方式二:
OPTIONS (skip=1,rows=128) – sqlldr 命令显示的选项可以写到这里边来,skip=1 用来跳过数据中的第一行
LOAD DATA
INFILE “c: \dept1.csv” --指定外部数据文件,可以写多个 INFILE “another_data_file.csv” 指定多个数据文件
–这里还可以使用 BADFILE、 DISCARDFILE 来指定坏数据和丢弃数据的文件,
append --操作类型,用 truncate table 来清除表中原有记录
INTO TABLE dept1 – 要插入记录的表
Fields terminated by “,” – 数据中每行记录用 “,” 分隔
Optionally enclosed by ‘"’ – 数据中每个字段用 ‘"’ 框起,比如字段中有 “,” 分隔符时
trailing nullcols --表的字段没有对应的值时允许为空
(
virtual_column FILLER, --跳过由 PL/SQL Developer 生成的第一列序号
deptno ,–“dept_seq.nextval”, --这一列直接取序列的下一值,而不用数据中提供的值
dname ,–"'Hi '||upper(:dname)",–,还能用 SQL 函数或运算对数据进行加工处理
loc
)

说明:在操作类型 truncate 位置可用以下中的一值:

  1. insert --为缺省方式,在数据装载开始时要求表为空
  2. append --在表中追加新记录
  3. replace --删除旧记录(用 delete from table 语句),替换成新装载的记录
  4. truncate --删除旧记录(用 truncate table 语句),替换成新装载的记录
    执行命令
    Sqlldr scott/tiger control=dept1.ctl
    看看日志文件, 坏数据文件,从中可让你更好的理解 Sql Loader,里面有对控制文件的解析、列出每个字段的类型、
    加载记录的统计、出错原因等信息

–练习--------------------------------------------------------------------------

–统计两个字段出现的次数
create table test_eap_one
(
pid varchar2(20),
dept varchar2(20)
);
insert into test_eap_one values(‘111’,‘aaaa’);
insert into test_eap_one values(‘222’,‘aaaa’);
insert into test_eap_one values(‘111’,‘bbbb’);
insert into test_eap_one values(‘222’,‘bbbb’);
insert into test_eap_one values(‘333’,‘dddd’);
insert into test_eap_one values(‘111’,‘aaaa’);
insert into test_eap_one values(‘333’,‘cccc’);
insert into test_eap_one values(‘333’,‘cccc’);
insert into test_eap_one values(‘444’,‘aaaa’);
insert into test_eap_one values(‘444’,‘aaaa’);
select pid,dept,count(*) as cnum from test_eap_one group by pid, dept;

/*
表一(AAA)
商品名称 mc 商品总量 sl
A 100
B 120
表二(BBB)
商品名称 mc 出库数量 sl
A 10
A 20
B 10
B 20
B 30
*/
–用一条 Transact-SQL 语句算出商品 A,B 目前还剩多少?
–这个as可写可不写
select aaa.mc,s1-e.sum_s1 as leave from aaa,(select sum(s1) sum_s1,mc from bbb group by mc) e where aaa.mc = e.mc;

–他会根据mc不一样,括号中的内容也显示不一样
select aaa.mc,aaa.s1-(select sum(bbb.s1) from bbb where bbb.mc = aaa.mc) from aaa;

insert into student values(1,‘小明’);
insert into student values(2,‘小花’);
insert into teacher values(1,‘陈红’);
insert into teacher values(2,‘陈白’);
insert into course values(1,‘语文’,‘文科’);
insert into course values(2,‘数学’,‘理科’);
–小明选了陈红老师的语文
insert into choose_course values(1,1,1,1);
–小明选了陈红老师的数学
insert into choose_course values(2,1,1,2);
–小花选了陈红老师的数学
insert into choose_course values(3,2,1,2);
–小明选了陈白老师的语文
insert into choose_course values(1,1,2,1);
–小花选了陈红老师的语文
insert into choose_course values(4,2,1,1);

–查找陈红老师教的学生是那些?
select * from student stu where stu.sid in (select distinct cc.sid from teacher t,choose_course cc where t.tid = cc.tid and t.tname=‘陈红’);
select distinct s.* from teacher t,choose_course cc,student s where t.tid = cc.tid and t.tname=‘陈红’ and s.sid = cc.sid;
–找学生小明所有的文科老师?
select * from teacher where tid in (select distinct tid from choose_course cc,student s,course c where cc.sid = s.sid and cc.cid = c.cid and s.sname = ‘小明’ and c.ctype = ‘文科’ );
select distinct t.* from teacher t,choose_course cc,student s,course c where cc.sid = s.sid and cc.cid = c.cid and s.sname = ‘小明’ and c.ctype = ‘文科’ and t.tid = cc.tid;
–找出没有选修陈白老师的学生
select * from student stu where stu.sid not in (select cc.sid from teacher t,choose_course cc where t.tid = cc.tid and t.tname=‘陈白’);
–教的学生最少的老师?
select t.tid,t.tname,t2.cou from teacher t,( select tid,cou from (select tid,count(distinct sid) cou from choose_course group by tid order by cou) t1 where rownum=1) t2 where t.tid = t2.tid;
select t.* from teacher t where t.tid = (select tid from (select tid,count(distinct sid) cou from choose_course group by tid order by cou) t1 where rownum=1);

–插入人员表的数据
insert into person values(1,‘a’);
insert into person values(2,‘b’);
–插入打卡的数据
insert into card values(1,to_date(‘20090719080200’,‘yyyymmddhh24miss’),1);
insert into card values(2,to_date(‘20090719180200’,‘yyyymmddhh24miss’),1);
insert into card values(3,to_date(‘20090719090200’,‘yyyymmddhh24miss’),2);
insert into card values(4,to_date(‘20090719170200’,‘yyyymmddhh24miss’),2);
insert into card values(5,to_date(‘20090720080200’,‘yyyymmddhh24miss’),1);
insert into card values(6,to_date(‘20090720160200’,‘yyyymmddhh24miss’),1);
insert into card values(7,to_date(‘20090720070200’,‘yyyymmddhh24miss’),2);
insert into card values(8,to_date(‘20090720200200’,‘yyyymmddhh24miss’),2);

–分析:先分组统计出每个人,每天的上班时间和下班时间 即(id,day,mindate,maxdate)
select p.pid as id,
to_char(c.ctime,‘yyyymmdd’) as day,
to_char(min(c.ctime),‘hh24mi’) as mindate,
to_char(max(c.ctime),‘hh24mi’) as maxdate
from card c,person p where c.cuser = p.pid group by p.pid,to_char(c.ctime,‘yyyymmdd’);

–把上面的分析做成一个视图,判断上班时间是否为迟到和下班时间是否为早退
– 如果判断前1天的打卡记录,就改成
to_char(c.ctime,‘yyyymmdd’)<=to_char(sysdate-10,‘yyyymmdd’)
–8:00–12:00为迟到,12:00–18:00 为早退
select p.name as person_name,
e1.day as work_day,
e1.mindate as AM,
e1.maxdate as PM,
–判断迟到
case
when e1.mindate between ‘0800’ and ‘1200’ then ‘yes’
else ‘no’
end as later,
–判断早退
case
when e1.maxdate between ‘1201’ and ‘1800’ then ‘yes’
else ‘no’
end as leave_early
from
–员工表
person p,
–上面那张视图表
(select
p.pid as id,
to_char(c.ctime,‘yyyymmdd’) as day,
to_char(min(c.ctime),‘hh24mi’) as mindate,
to_char(max(c.ctime),‘hh24mi’) as maxdate
from card c,person p
where
c.cuser = p.pid and to_char(c.ctime,‘yyyymmdd’)<=to_char(sysdate-1,‘yyyymmdd’)
group by p.pid,to_char(c.ctime,‘yyyymmdd’)
) e1
where p.pid = e1.id;

–删除一张表重复记录(ID 是自增唯一,重复记录:其他字段都是一样)
insert into aa values(1,‘louis’,20);
insert into aa values(2,‘louis’,20);
insert into aa values(3,‘jimmy’,30);
insert into aa values(4,‘louis’,20);
delete from aa where id not in(select min(id) from aa group by name,num);
select a1.id from aa a1,aa a2 where a1.id>a2.id and a1.name=a2.name and a1.num=a2.num;

create table student1
(
name varchar2(20),
kecheng varchar2(20),
fenshu number(6)
);
insert into student1 values(‘张三’,‘语文’,81);
insert into student1 values(‘张三’,‘数学’,75);
insert into student1 values(‘李四’,‘语文’,76);
insert into student1 values(‘李四’,‘数学’,90);
insert into student1 values(‘王五’,‘语文’,81);
insert into student1 values(‘王五’,‘数学’,100);
insert into student1 values(‘王五’,‘英语’,90);
–查询出每门课都大于80分的学生姓名
select Distinct name from student1 A Where Not Exists(Select * from student1 Where Name =A.Name And fenshu<=80);
select name from student1 group by name having min(fenshu)>80;
select Distinct name from student1 where name not in(select name from student1 where fenshu<=80);

create table test1
(
fid number(6),
fno number(10)
);
insert into test1 values(101,1001);
insert into test1 values(101,1001);
insert into test1 values(102,1002);
insert into test1 values(102,1003);
insert into test1 values(103,1004);
insert into test1 values(104,1005);
insert into test1 values(104,1006);
insert into test1 values(105,1007);
insert into test1 values(105,1007);
insert into test1 values(105,1007);
insert into test1 values(105,1008);
–列出该表中一个 FID 对应多个不同的 Fno 的纪录。
select distinct fid,fno from test1 where fid in (select fid from test1 group by fid having count(distinct fno)>1) order by fid asc;

/*
有员工表 empinfo
(
Fempno varchar2(10) not null pk,
Fempname varchar2(20) not null,
Fage number not null,
Fsalary number not null
);
假如数据量很大约 1000 万条;写一个你认为最高效的 SQL,用一个 SQL 计算以下四种人:
fsalary>9999 and fage > 35
fsalary>9999 and fage < 35
fsalary<9999 and fage > 35
fsalary<9999 and fage < 35
每种员工的数量;
*/
select sum(
case when tt.fsalary>9999 and fage > 35
then 1
else 0
end
) as ‘fsalary>9999 and fage > 35’,
sum(
case when tt.fsalary>9999 and fage < 35
then 1
else 0
end
) as ‘fsalary>9999 and fage < 35’,
sum(case when tt.fsalary<9999 and fage > 35
then 1
else 0
end) as ‘fsalary<9999 and fage > 35’,
sum(case when tt.fsalary<9999 and fage < 35
then 1
else 0
end) as ‘fsalary>9999 and fage < 35’
from empinfo tt;

create table test2
(
date1 date,
cj varchar2(20)
);
insert into test2 values(to_date(‘2005-05-09’,‘yyyy-MM-dd’),‘胜’);
insert into test2 values(to_date(‘2005-05-09’,‘yyyy-MM-dd’),‘胜’);
insert into test2 values(to_date(‘2005-05-09’,‘yyyy-MM-dd’),‘负’);
insert into test2 values(to_date(‘2005-05-09’,‘yyyy-MM-dd’),‘负’);
insert into test2 values(to_date(‘2005-05-10’,‘yyyy-MM-dd’),‘胜’);
insert into test2 values(to_date(‘2005-05-10’,‘yyyy-MM-dd’),‘负’);
insert into test2 values(to_date(‘2005-05-10’,‘yyyy-MM-dd’),‘负’);
select date1,sum(case when cj=‘胜’ then 1 else 0 end) as 胜,sum(case when cj=‘负’ then 1 else 0 end) as 负 from test2 group by date1;

create table table1
(
mon varchar2(50),
dept varchar2(10),
yj number(5)
);
insert into table1 values(‘一月份’,‘01’,10);
insert into table1 values(‘一月份’,‘02’,10);
insert into table1 values(‘一月份’,‘03’,5);
insert into table1 values(‘二月份’,‘02’,8);
insert into table1 values(‘二月份’,‘04’,9);
insert into table1 values(‘三月份’,‘03’,8);

create table table2
(
dept varchar2(10),
dname varchar2(50)
);
insert into table2 values(‘01’,‘国内业务一部’);
insert into table2 values(‘02’,‘国内业务二部’);
insert into table2 values(‘03’,‘国内业务三部’);
insert into table2 values(‘04’,‘国际业务部’);
insert into table2 values(‘05’,‘其他部门’);

select a.dept,a.dname,
sum(case when b.mon=‘一月份’ then b.yj else 0 end) as 一月份,
sum(case when b.mon=‘二月份’ then b.yj else 0 end) as 二月份,
sum(case when b.mon=‘三月份’ then b.yj else 0 end) as 三月份
from table2 a left join table1 b on a.dept=b.dept group by a.dept,a.dname order by a.dept asc;

create table s
(
sno number(6),
sname varchar2(20),
sdw varchar2(20),
sxy varchar2(20)
);
insert into s values(1001,‘刘一’,‘中国’,‘理院’);
insert into s values(1002,‘刘二’,‘美国’,‘科院’);
insert into s values(1003,‘刘三’,‘法国’,‘文院’);

create table c
(
cno varchar2(10),
cname varchar2(20)
);
insert into c values(‘c1’,‘语文’);
insert into c values(‘c2’,‘数学’);
insert into c values(‘c3’,‘英语’);
insert into c values(‘c4’,‘物理’);
insert into c values(‘c5’,‘化学’);
insert into c values(‘c6’,‘生物’);

create table sc
(
sno number(6),
cno varchar2(10),
snum number(6)
);
insert into sc values(1001,‘c1’,99);
insert into sc values(1001,‘c2’,89);
insert into sc values(1001,‘c3’,79);
insert into sc values(1001,‘c4’,69);
insert into sc values(1001,‘c5’,59);
insert into sc values(1001,‘c6’,49);

–嵌套语句查询选修课程编号为‘C2’的学员姓名和所属单位
select sname,sdw from s where sno in (select sno from sc where cno=‘c1’);

–查询选修全部课程的学员姓名和所属单位。
select sname,sdw from s where not exists (select * from c where not exists (select * from sc where sc.sno=s.sno and sc.cno=c.cno));

–选修课超过5门的学员学号和所属单位
select sno,sdw from s where sno in–落在某个空间里
(
select sno from sc
group by sno having count(*)>5
);

–找出部门10中的经理(MANAGER)和部门20中的普通员工(CLERK)
select * from emp where (deptno=10 and job=‘MANAGER’) or (deptno=20 and job=‘CLERK’);
–找出部门 10 中既不是经理也不是普通员工,而且工资大于等于 2000 的员工
select * from emp where deptno=10 and job not in(‘MANAGER’,‘CLERK’) and sal>=2000;
–找出有奖金的员工的不同工作
Select distinct job from emp where comm is not null and comm>0;
–找出没有奖金或者奖金低于 500 的员工
Select * from emp where comm<500 or comm is null;
–显示雇员姓名,根据其服务年限,将最老的雇员排在最前面
select ename from emp order by hiredate;
–列出所有员工的姓名和其上级的姓名
select e1.ename as lower ,e2.ename as upper from emp e1,emp e2 where e1.mgr = e2.empno;
–列出员工表中每个部门的员工数(员工数必须大于 3),和部门名称
select d.* ,ed.cou from dept d,(select deptno,count() cou from emp group by deptno having count()>3) ed where d.deptno=ed.deptno;
–以职位分组,找出平均工资最高的两种职位
select * from ( select emp.job,avg(sal) a from emp group by job order by a desc ) where rownum ❤️;

–查找出不在部门 20,且比部门 20 中任何一个人工资都高的员工姓名、部门名称
Select e.ename,d.dname from emp e,dept d where e.deptno!= 20 and e.sal>(select max(sal) from emp where deptno=20) and e.deptno=d.deptno;

–得到平均工资大于 2000 的工作职种
select job,avg(sal) from emp group by job having avg(sal) > 2000;

–分部门得到工资大于 2000 的所有员工的平均工资,并且这几个员工的平均工资还要大于2500
select deptno,avg(sal) from emp where sal>2000 group by deptno having avg(sal)>2500;

–得到每个月工资总数最少的那个部门的部门编号,部门名称,部门位置
select * from dept where deptno=( select e.deptno from ( select deptno,sum(sal) from emp group by deptno order by sum(sal) ) e where rownum=1 );

–分部门得到平均工资等级为 4级(等级表)的部门编号
select new.dno from salgrade sa,(select deptno as dno,avg(sal) as avgsal from emp group by deptno) new where sa.grade=4 and new.avgsal between sa.losal and sa.hisal;

–查找出部门 10 和部门 20 中,工资最高第 3 名到工资第 5 名的员工的员工名字,部门名字,部门位置
select emp.ename,dept.dname,dept.loc from emp,dept,(select rownum no,new.* from (select * from emp where emp.deptno = 10 or deptno = 20 order by emp.sal desc) new) e where emp.deptno = dept.deptno and e.no >=3 and e.no <=5 and e.empno = emp.empno;

–查找出收入(工资加上奖金),下级比自己上级还高的员工编号,员工名字,员工收入
select e.ename,e.empno,e.sal+nvl(e.comm,0) from emp e,emp m where e.mgr = m.empno and (e.sal+nvl(e.comm,0)) >(m.sal+nvl(m.comm,0));

–查找出工资等级不为 4 级的员工的员工名字,部门名字,部门位置
select ename,dname,loc,sal from dept d,(select emp.deptno,emp.ename,emp.sal from emp,salgrade where sal between losal and hisal and grade !=4) new where d.deptno = new.deptno;
select e.ename,d.dname,d.loc from emp e,dept d,(select * from salgrade where grade=4) s where e.deptno=d.deptno and (e.sal<s.losal or e.sal>s.hisal);

–查找出职位和’MARTIN’ 或者’SMITH’一样的员工的平均工资
select avg(sal) from emp where job in (select job from emp where ename=‘MARTIN’ or ename=‘SMITH’);

–查找出不属于任何部门的员工
select * from emp where deptno is null or deptno not in(select deptno from dept);

–按部门统计员工数,查处员工数最多的部门的第二名到第五名(列出部门名字,部门位置)
select dept.dname, dept.loc from (select rownum no, deptno from (select count(*) employeeSum,deptno from emp group by deptno order by employeeSum desc)) e,dept where e.no between 2 and 5 and e.deptno = dept.deptno;

–查询出 king 所在部门的部门号\部门名称\部门人数
select t.countno,d.dname,d.loc,d.deptno from dept d,(select count() countno,deptno from emp where deptno in (select deptno from emp where ename = ‘KING’) group by deptno ) t where d.deptno = t.deptno;
select t2.countnum,d.dname,d.loc,d.deptno from dept d,(select t.countnum,t.deptno from (select count(empno) countnum,deptno from emp group by deptno) t where t.deptno in (select deptno from emp where lower(ename) = ‘king’)) t2 where t2.deptno=d.deptno;
select e.deptno as 部门号,d.dname as 部门名称,(select count(
) from (select deptno from emp where deptno in (select deptno from emp where ename=‘KING’))) as 部门人数 from emp e,dept d where e.deptno = d.deptno and e.ename = ‘KING’;

–查询出 king 所在部门的工作年限最大的员工名字
select ename,hiredate from emp where hiredate in (select min(hiredate) from emp where deptno in (select deptno from emp where ename=‘KING’));

–查询出工资成本最高的部门的部门号和部门名称
select d.deptno,d.dname,t.sum_sal from dept d,(select deptno,sum(sal) sum_sal from emp group by deptno having sum(sal) = (select max(sum(sal)) from emp group by deptno)) t where d.deptno = t.deptno;
select d.deptno,d.dname,t.sum_sal from dept d,(select * from (select deptno,sum(sal) sum_sal from emp group by deptno order by sum(sal) desc) where rownum<=1) t where d.deptno = t.deptno;

–查询员工信息与其中工资最高最低员工
select ename,sal,max(sal) over(), min(sal) over() from emp;

–根据子串分组
Select to_char(hiredate,‘yyyy’),avg(sal) from emp group by to_char(hiredate,‘yyyy’);

–确定一年内的天数
select add_months(trunc(sysdate,‘y’),12) - trunc(sysdate,‘y’) from dual;

–查询 EMP 员工表下每个部门工资前二名的员工信息
select deptno, ename, sal from emp e1 where (select count(1) from emp e2 where e2.deptno=e1.deptno and e2.ename!=e1.ename and e2.sal>e1.sal) <2 order by deptno, sal desc;
select * from (select deptno,ename,sal,row_number() over (partition by deptno order by sal desc) rn from emp) where rn<3;

–student,course,choose_course,找出选了所有课程的学生信息
select distinct sname from student s where not exists(select * from course c where not exists(select * from choose_course cc where s.sid=cc.sid and c.cid = cc.cid));
select student_id,count(distinct cid) from choose_course group by student_id having count(distinct cid) = (select count(distinct cid) from course);

–为所有人长工资,标准是: 10 部门长 10%; 20 部门长 15%; 30 部门长 20%其他部门长18%(要求用 DECODE 函数)
update emp set sal=decode(deptno,‘10’,sal*(1+0.1), ‘20’,sal*(1+0.15), ‘30’,sal*(1+0.2),sal*(1+0.18));

–根据工作年限长工资,标准是:为公司工作了几年就长几个百分点。
update emp set sal= round(sal * (1+(sysdate - hiredate)/365/100),2);

SELECT COUNT(1) FROM VPROCESS;−−查看当前的连接数SELECTVALUEFROMVPROCESS;--查看当前的连接数 SELECT VALUE FROM VPROCESS;−−查看当前的连接数SELECTVALUEFROMVPARAMETER WHERE NAME = ‘PROCESSES’;–查看数据库允许的最大连接数
ALTER SYSTEM SET PROCESSES = 500 SCOPE = SPFILE;–修改最大连接数
SHUTDOWN IMMEDIATE;–关闭数据库
STARTUP;–启动数据库
SELECT OSUSER, A.USERNAME, CPU_TIME/EXECUTIONS/1000000||‘S’, SQL_FULLTEXT, MACHINE FROM VSESSIONA,VSESSION A, VSESSIONA,VSQLAREA;–查看当前有哪些用户正在使用数据库

SELECT SUM(bytes) / (1024 * 1024) AS free_space, tablespace_name FROM dba_free_space GROUP BY tablespace_name;

–查询表空间的使用情况
SELECT a.tablespace_name, a.bytes total, b.bytes used, c.bytes free, (b.bytes * 100) / a.bytes "% USED ", (c.bytes * 100) / a.bytes "% FREE "
FROM sys.smtsavaila,sys.smts_avail a, sys.smtsa​vaila,sys.smts_used b, sys.sm$ts_free c
WHERE a.tablespace_name = b.tablespace_name
AND a.tablespace_name = c.tablespace_name;

–查询表空间的数据位置及是否启动了自动增长
SELECT FILE_NAME,TABLESPACE_NAME,AUTOEXTENSIBLE FROM dba_data_files;

–为表空间增容
ALTER DATABASE DATAFILE ‘C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\ex_data’ AUTOEXTEND ON NEXT 50M

–查看表空间大小上限,MAX_BYTES的值为-1表示无限制
select * from user_ts_quotas;

–为表空间新建一个数据容量
alter tablespace USERS add datafile ‘C:\APP\ADMINISTRATOR\ORADATA\GEOGLOBE\USERS02.DBF’ size 1000m autoextend on next 100m;

–Pluggable Database (PDB) 的自动startup
–默认情况下,在CDB 启动的时候,all 的PDB 都是mount状态,也没有默认的机制,在CDB启动时自动启动PDB。
–但这里可以通过触发器来实现PDB的自动open:
ALTER SESSION SET CONTAINER = CDB$ROOT;–在CDB模式下创建这个触发器

CREATE OR REPLACE TRIGGER open_pdbs
AFTER STARTUP ON DATABASE
BEGIN
EXECUTE IMMEDIATE ‘ALTER PLUGGABLE DATABASE ALL OPEN’;
END open_pdbs;
/

–判断当前是一年中的第几周
SELECT TO_CHAR(SYSDATE, ‘WW’) FROM DUAL;

Oracle数据库使用教程相关推荐

  1. Oracle数据库基础教程:入门其实很简单

    为什么80%的码农都做不了架构师?>>>    Oracle数据库基础教程:入门其实很简单 Oracle数据库系统是目前最流行的客户/服务器数据库之一.本文集从初学者的角度出发,由浅 ...

  2. Oracle数据库基础教程

    查看书籍详细信息: Oracle数据库基础教程 编辑推荐 体现作者多年的数据库管理与开发经验,结合大量实用技巧,重点突出,便于灵活掌握,提供典型应用实例与上机实验,分析详细,实用性强. 本书是作者结合 ...

  3. oracle如何导入excel数据库文件,如何将excel导入oracle数据库的教程

    在Excel中录入好数据以后就需要导入到oracle数据库,或许有些朋友不知道该如何做.下面是学习啦小编带来的关于如何将excel导入oracle数据库的教程,欢迎阅读! 如何将excel导入orac ...

  4. oracle数据库实战教程 李兴华ORACLE入门到精通教程

    oracle视频教程有很多,但经典教程却非常少, 这里推荐李兴华ORACLE入门到精通教程,可以让大家快速的学习oracle数据库! Mysql数据库和oracle数据库有什么区别 Mysql是中小型 ...

  5. csdn涨薪技术-软件测试Oracle数据库全套教程

    1.什么是数据库? >> 存储数据的仓库 [文章末尾给大家准备了大量的福利哦] 2.常见的数据库有哪些? Oracle>>甲骨文 Mysql>>甲骨文 SQLSer ...

  6. 超简单的Oracle 数据库安装教程

    安装包下载地址 https://www.oracle.com/cn/database/technologies/oracle-database-software-downloads.html#19c ...

  7. 【详细】Oracle数据库安装教程--Oracle DataBase 19c

    目录 前言/背景 1.下载Oracle 19c数据库 1. Oracle官网下载 2. 网盘下载 3. 安装及使用 2.Oracle管理工具 前言/背景 Oracle Database 19c 是最新 ...

  8. Oracle数据库学习教程

    Oracle数据库 1.1 数据库环境安装 1.Oracle数据库产品是免费的,我们可以从Oracle的官方网站(http://www.oracle.com)下载到程序安装包,Oracle在Windo ...

  9. oracle数据库切换教程,oracle 11gR2 物理备用数据库搭建及切换

    在同一台机器上搭建物理备用数据库的步骤,linux环境 oracle 11.2.0.1 主库:orcl 备库:stby 1 检查侦听是否启动 2 配置主备数据库的初始化参数文件 sqlplus /as ...

  10. 学习Oracle数据库入门到精通教程资料合集

    任何大型信息系统,都需要有数据库管理系统作为支撑.其中,Oracle以其卓越的性能获得了广泛的应用.本合集汇总了学习Oracle数据库从入门到精通的30份教程资料. 资料名称 下载地址 超详细Orac ...

最新文章

  1. Mysql高级调优篇——第五章:Sql调优在面试中深度剖析
  2. python对话框代码_Python、tkinter、复杂对话框和代码结构
  3. python程序一定要有主函数_Python 没有main函数的原因
  4. Wi-Fi模块的设置方法汇总
  5. 使用Tomcat Native提升Tomcat IO效率
  6. php如何拼接变量名,php动态拼接变量名,可变变量,动态变量,使用花括号,使用两个$符...
  7. 使用Forms Authentication实现用户注册、登录 (三)用户实体替换
  8. 微软亚研院华刚对科研的见解
  9. 【OCR三】大批量生成文字训练集(转)
  10. QT实现“摇摇乐抽奖”(Lottery和Lottery2)
  11. Excel2016保存文件闪退(在安装了Visio后)
  12. ubuntu14.04 + dlib19.2+【 C++ 】+Face Landmark Detection
  13. vue中组件根元素添加样式无效
  14. lagrange量中的u和v的来历
  15. win8.1各版本的区别
  16. hdd硬盘与sas硬盘_什么是硬盘驱动器(HDD)?
  17. linux系统相关文件夹讲解,Linux中重要文件夹介绍PPT课件
  18. MySQL数据库复制概论
  19. 批处理图片尺寸修改成4的倍数
  20. 公众号第三方平台开发 教程一 创建公众号第三方平台

热门文章

  1. mo java_mojava和 high sierra系统区别?
  2. 在东京大学感受_东京最好的街头小吃在哪里找到
  3. 使oracle支持dbo,Oracle.ManagedDataAccess.EntityFramework – ORA-01918:用户’dbo’不存在
  4. 怎样在你的团队做 Code Review ?
  5. 学习计算机基础有什么推荐的书和视频?
  6. Java加密知识体系
  7. Android Property服务
  8. HDU - 6070
  9. lanhelper1.83 注册
  10. 写给那些让我糊里糊涂的HTTP、TCP、UDP、Socket