plsql连接oracle服务器
用户:scott
密码:自己设置的密码
连接的数据库:orcl
默认情况下scott用户只有四张表
emp,bonus,dept,salgrade
用户管理
创建用户账户
查看用户账户
oracle的概要资源
模式
表空间
权限管理
DML:Data Manipulation Language 数据操纵语言
DDL:Data Definition Language 数据定义语言
DCL: Data Control Language 数据控制 语言
DDL用于定义数据库的结构,比如创建,修改或者删除数据库对象,如下操作
DML用于查询和修改数据记录,包括如下操作
其中select是sql语言的基础,最为重要
DCL用来控制数据库访问,包括如下操作
语法:SELECT * |{ [DISTINCT] column | expression [alias],...} FROM TABLE
;
SELECT 标识 选择那些列
FROM 标识从哪个表中选择
选择全部列
SELECT * FROM EMP;
选择特定的列
SELECT EMPNO , ENAME FROM EMP ;
注意:
SQL语言大小写不敏感
SQL可以写在一行或者多行
关键字不能缩写或者分行
各字句一般要分行写
使用缩进提高语句的可读性
算数运算符
操作符 | 描述 |
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
SELECT ENAME , SAL,SAL+100 FROM EMP ;
操作符优先级
SELECT ENAME , SAL , SAL*3+300 FROM emp;
使用括号
SELECT ENAME , sal , 10 * (sal + 100) FROM EMP ;
定义空值
/*定义空值*/
SELECT ENAME , SAL ,COMM FROM EMP ;
空值在数学运算中的使用
-- 包含空值的数学表达式的值都是空值
SELECT ENAME , 10*SAL*COMM FROM EMP ;
列的别名
as
,别名使用双引号,以便在别名中包含空格或者特殊字符区分大小写使用别名
SELECT ENAME NAME,SAL*10 sSL FROM emp;
连接符
SELECT empno||ename empnew FROM emp;
字符串
SELECT
列表中一个字符,数字,日期SELECT ename || 'is a ' || sal AS EMPDETAILS FROM emp;
重复行
默认情况,查询返回所有行,包括重复的行
/*重复行*/
SELECT JOB FROM emp;
/*删除重复行*/
SELECT DISTINCT job FROM emp;
SQL
SQL Plus
可以描述表结构
编辑SQL语句
执行SQL语句
将SQL保存在文件中并且将SQL语句执行结果保存在文件中
在保存的文件中执行语句
将文本文件装入sql plus编辑窗口
显示表结构
desc emp ;
describe emp ;
过滤
WHERE
子句,将不满足条件的行过滤掉SELECT *|{[DISTINCT] column|expression [alias]...} FROM TABLE WHERE conditions
SELECT * FROM emp WHERE sal > 200 ;
字符和日期
SELECT * FROM emp WHERE ename = 'ALLEN' ;
SELECT * FROM emp WHERE HIREDATE = '20-2月-1981';
比较运算
操作符 | 含义 |
= | 等于(不是==)注意:赋值是=》:= |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
<> | 不等于(也可以是!=) |
SELECT * FROM emp WHERE sal <= 800 ;
其他比较运算
操作符 | 含义 |
BETWEEN...AND... | 两个值之间 |
IN | 等于值列表中的一个 |
LIKE | 模糊查询 |
IS NULL | 空值 |
BETWEEN
使用between运算显示一个区间内的值
SELECT * FROM emp WHERE sal BETWEEN 800 AND 1000 ;
IN
使用IN关键字显示列表中值
SELECT * FROM emp WHERE empno IN (7369,7370,7371) ;
Like
SELECT * FROM emp WHERE empno LIKE '74%';
SELECT * FROM emp WHERE empno LIKE '_4%';
回避特殊符号的:使用转义符。例如
将[%]转为[%]、[_]转为[_],然后再加上[ESCAPE ‘’]即可
SELECT * FROM emp WHERE empno LIKE '73_%' ESCAPE '\';
NULL
使用 IS NULL 判断空值
SELECT * FROM emp WHERE comm IS NULL ;
逻辑运算
操作符 | 含义 |
AND | 逻辑并 |
OR | 逻辑或 |
NOt | 逻辑否 |
AND
要求两边条件都是真
/*AND 逻辑与操作*/
SELECT * FROM emp WHERE sal >=800 AND comm IS NULL ;
OR
要求两边条件一边是真就行
SELECT * FROM emp WHERE sal >= 10000 OR empno LIKE '74%';
NOT
逻辑非操作
SELECT * FROM emp WHERE job NOT IN ('CLERK','MANAGER') ;
优先级
优先级 | |
1 | 算术运算符 |
2 | 连接符 |
3 | 比较符 |
4 | is null , like, in |
5 | between |
6 | not |
7 | and |
8 | or |
ORDER BY
# 降序
SELECT * FROM emp ORDER BY empno DESC;
# 升序
SELECT * FROM emp ORDER BY empno ;
# 按照别名排序
SELECT empno , sal*20+200 newsal FROM emp ORDER BY newsal DESC ;
两种函数
单行函数
function_name(arg1,arg2,...)
字符函数
大小写控制函数
LOWER,UPPER,INITCAP
函数名 | 函数说明 | 函数语法 |
CONCAT | 将多个字符串连接成一个字符串 | concat(str1, str2,...) 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。 |
SUBSTR | 字符截取函数 | 格式1:substr(string str, int a, int b);1、string 需要截取的字符串 2、a 截取字符串的开始位置(注:当a等于0或1时,都是从第一位开始截取) 3、b 要截取的字符串的长度 格式2:substr(string string, int a) ; 1、str 需要截取的字符串 2、a 可以理解为从第a个字符开始截取后面所有的字符串。 |
LENGTH | 表示字符串长度 | length(str) |
INSTR | 字符查找函数 | INSTR( string, substring [, start_position [, th_appearance ] ] )string - 要搜索的字符串。字符串可以是CHAR,VARCHAR2,NCHAR,NVARCHAR2,CLOB或NCLOB等类型。 substring - 要在字符串(string)中搜索的子字符串。 子字符串可以是CHAR,VARCHAR2,NCHAR,NVARCHAR2,CLOB或NCLOB等类型。 start_position - 可选的。 在搜索将开始的字符串中的位置。 如果省略,则默认为1。字符串中的第一个位置为1.如果start_position为负数,INSTR函数会从字符串末尾开始计算start_position字符数,然后搜索字符串的开头。 nth_appearance - 可选的。 子串的第n个出现。 如果省略,则默认为1。 返回值:返回一个数字值。 字符串中的第一个位置是1。如果在字符串中找不到substring,那么INSTR函数将返回0。 |
LPAD | 用于往源字符串的左侧填充一些字符 | lpad( string1, padded_length, [ pad_string ] )tring1:源字符串padded_length:最终返回的字符串的长度,如果最终返回的字符串的长度比源字符串的小,那么此函数实际上对源串进行截断处理pad_string:用于填充的字符,可以不填,默认为空字符 |
RPAD | 往源字符串的右侧填充一些字符 (字符串string1不能为空). | RPAD( string1, padded_length [, pad_string] ) string1:源字符串. padded_length:要返回的字符长度。如果padded_length的值比原字符串的长度小,那么RPAD函数会对字符串进行截取处理。 pad_string:可以为空。用作填充的字符串。如果不填,默认为空格RPAD函数的返回值是字符串。 |
TRIM | 用来去除一个字符串的开头或结尾(或两者)的字符 | TRIM([ { { LEADING | TRAILING | BOTH } [ trim_character ] | trim_character } FROM ] trim_source ) leading 开头字符 trailing 结尾字符 both 开头和结尾字符 trim_character 去除的字符 trim_source 修剪源 |
REPLACE | 用另外一个值来替代串中的某个值。 | REPLACE ( char, search_string [, replace_string]) 如果没有指定replace_string 变量的值,那么当发现search_string 变量的值时,就将其删除。输入可以为任何字符数据类型——CHAR、VARCHAR2、NCHAR、NVARCHAR2、CLOB或NCLOB。 |
举例说明
LOWER:大写字符转换为小写字符
/*大写字符转换小写字符*/
SELECT job FROM emp;
SELECT LOWER(job) FROM emp;
UPPER:小写字符转换大写字符
/*小写字符转换为大写字符*/
SELECT class_name FROM stu_class;
SELECT UPPER(class_name) FROM stu_class;
INITCAP:每个单词的第一个字母大写,其它字母变为小写返回. 单词由空格,控制字符,标点符号等非字母符号限制.
/*INITCAP将字符串首字母变为大写,剩余字符小写*/
SELECT INITCAP('mr pmb') FROM dual;
CONCAT:将多个字符串连接成一个字符串
/*CONCAT:将多个字符串连接成一个字符串*/
SELECT CONCAT('a', 'b', 'c') FROM dual;
/*concat连接多个字符时,需要嵌套*/
SELECT CONCAT(CONCAT('a', 'b'), 'c') FROM dual;
SUBSTR:字符截取函数
/*SUBSTR:字符截取函数*/
SELECT * FROM emp ;
/*第一个数字0或者1时候,都是从第一位开始截取*/
SELECT SUBSTR(ename,0,1) FROM emp ;
SELECT SUBSTR(ename,1,1) FROM emp ;
SELECT ename FROM emp;
/*从第一个字符截取后面所有的字符串(0,1结果都是所有字符串)*/
SELECT SUBSTR(ename,0) FROM emp ;
SELECT SUBSTR(ename,1) FROM emp ;
/*从第二个字符截取后面所有的字符串*/
SELECT SUBSTR(ename,2) FROM emp ;
LENGTH:表示字符串长度
/*LENGTH:表示字符串长度*/
SELECT ename,LENGTH(ename) FROM emp;
INSTR:字符查找函数
/*默认第一次出现 'o'的位置 4*/
SELECT INSTR('ello','o') FROM dual ;
/*也就是说:在"helloworld"的第2(e)号位置开始,查找第二次出现的“l”的位*/
/* instr(源字符串, 目标字符串, 起始位置, 匹配序号)*/
SELECT INSTR('helloworld' , 'l',2,2) FROM dual;
LPAD|RPAD:用于往源字符串的左侧填充一些字符
/*LPAD|RPAD:用于往源字符串的左侧填充一些字符*/
/**
* 'acb':源字符串
* 10:填充之后的总字符个数
* 's': 需要填充的字符
**/
SELECT LPAD('acb',10,'e') FROM dual ;
-- 返回结果 eeeeeeeacb
SELECT RPAD('acb',10,'e') FROM dual ;
-- 返回结果 acbeeeeeee
TRIM:用来去除一个字符串的开头或结尾(或两者)的字符
/*TRIM:用来去除一个字符串的开头或者结尾*/
/*第一种场景:删除空格*/
/*去除字符串前后空格*/
SELECT ' sd abc ',TRIM(' sd abc ') FROM dual;
/*LTRIM去除指定字符的前面空格*/
SELECT ' sd abc ',LTRIM(' sd abc ') FROM dual;
/*RTRIM去除指定字符后面后空格*/
SELECT ' sd abc ',RTRIM(' sd abc ') FROM dual;
/*第二种场景:去除指定的字符。trim只能去除单个字符,而ltrim和rtrim可以去除多个字符*/
/*表示字符串string2去除前面|后面|前后面(leading|trailing|both)的字符string1,默认去除方式为both*/
/*去除字符串 'abnds' 中 'b'(前面)的 字符*/
SELECT TRIM(LEADING 'b' FROM 'abnds') FROM dual;
/*去除字符串 'nnanbndsn' 中 'n'(两侧)的 字符*/
SELECT TRIM(both 'n' FROM 'nnanbndsn') FROM dual;
/*去除字符串 'abnds' 中 's'(后面)的 字符*/
SELECT TRIM(TRAILING 's' FROM 'abnds') FROM dual;
REPLACE:用另外一个值来替代串中的某个值
/*REPLACE:用另外一个值替代串中的某个值*/
SELECT REPLACE('abcdefg','a','0') FROM dual ;
/*返回结果:0bcdefg*/
SELECT REPLACE('abcdefg','a') FROM dual ;
/*返回结果:bcdefg*/
数字函数
语法:ROUND(number[,decimals])
number 待做截取处理的数值
decimals 指明需保留小数点后面的位数。可选项,忽略它则截去所有的小数部分,并四舍五入。如果为负数则表示从小数点开始左边的位数,相应整数数字用0填充,小数被去掉。需要注意的是,和trunc函数不同,对截取的数字要四舍五入。
作用:截取数字
案例:
/*截取数字:round*/
SELECT ROUND(123.456,3) FROM dual ; -- 123.456
SELECT ROUND(123.456,2) FROM dual ; -- 123.46
SELECT ROUND(123.456,1) FROM dual ; -- 123.5
语法:TRUNC(date,[fmt])
date 为必要参数,是输入的一个日期值 fmt 参数可忽略,是日期格式,用以指定的元素格式来截去输入的日期值。忽略它则由最近的日期截去
TRUNC(number[,decimals]) 其中: number 待做截取处理的数值 decimals 指明需保留小数点后面的位数。可选项,忽略它则截去所有的小数部分。
作用:以指定元素格式截去一部分的日期值或者只是该函数不对指定小数前或后的部分做相应舍入选择处理,而统统截去。
案例:
/*以指定元素格式截去一部分的日期值*/
SELECT TRUNC(SYSDATE, 'yyyy') FROM dual; -- 2022/01/01 返回当年第一天
SELECT TRUNC(SYSDATE, 'mm') FROM dual; -- 2022/01/01 返回当月第一天
SELECT TRUNC(SYSDATE, 'd') FROM dual; -- 2022/01/01 返回当周第一天
SELECT TRUNC(12.345, 2) FROM dual; -- 12.34
SELECT TRUNC(12.345) FROM dual; -- 12.3
SELECT TRUNC(12.345,-1) FROM dual; -- 10 此时 小数点左边指定位数后面的部分截去,均以0记
SELECT TRUNC(12.345,-2) FROM dual; -- 0 此时 小数点左边指定位数后面的部分截去,均以0记
语法:mod(m,n)
MOD返回m除以n的余数,如果n是0,返回m,这个函数以任何数字数据类型或任何非数值型数据类型为参数,可以隐式地转换为数字数据类型。
案例:
/*mod:取余*/
SELECT MOD(12, 6) FROM dual; -- 0
SELECT MOD(12, 7) FROM dual; -- 5
SELECT MOD(-12, 7) FROM dual; -- -5
DUAL 是一个‘伪表’,可以用来测试函数和表达式
日期函数
oracle中的日期型数据实际包含两个值:日期和时间
sysdate函数返回 日期+时间
/*获取当前时间*/
SELECT SYSDATE FROM dual; -- 2022/1/13 20:28:21
日期的数学运算
1、日期上加上或者减去一个数字结果仍然是日期
SELECT sysdate,SYSDATE - 1 FROM dual ; -- 2022/1/13 20:32:09 2022/1/12 20:32:09
2、两个日期之间相减 为相差的天数
注意:日期不允许加法运算
/*两个日期之间相减 为相差的天数*/
SELECT SYSDATE-hiredate FROM emp;
3、可以使用数字除以24来向日期中加上或者减去天数
/*可以使用数字除以24来向日期中加上或者减去天数*/
SELECT SYSDATE+10/24 FROM DUAL ; -- 往后推迟一天
日期函数
months_between
语法:MONTHS_BETWEEN(DATE1,DATE2)
date1:靠前 date2:靠后
作用:两个日期相差的天数
案例:
SELECT months_between(SYSDATE,hiredate) FROM emp ;
add_months
add_months
语法:add_months(x,y)或者add_months(times,months)函数
这个函数用于计算在时间x之上加上Y个月后的时间值,要是Y的值为负数的话就是在
这个时间点之间的时间值(这个时间-Y个月)
作用:指定日期添加若干月份
案例:
/*指定日期添加若干月份*/
SELECT hiredate, add_months(hiredate, 1) FROM emp; -- 1980/12/17 1981/1/17
next_day
语法:
作用:指定日期的下一个星期*对应的日期
案例:
执行select sysdate from dual;得到当前日期为:2014/4/30 14:11:33 星期三
select next_day(sysdate,'星期日') from dual;
得到日期为:2014/5/4 14:12:53
从这个礼拜三到得到礼拜天的日期数
last_day
语法:last_day(date)
作用:指定日期对应月份的最后一天
案例:
/*指定日期的最后一天*/
SELECT last_day(SYSDATE) FROM dual; -- 2022/1/31 20:51:55
转换函数
数据类型转换
源数据类型 | 目标数据类型 |
VARCHAR2 OR CHAR | NUMBER |
VARCHAR2 OR CHAR | DATE |
NUMBER | VARCHAR2 |
DATE | VARCHAR2 |
TO_CHAR函数对日期的转换
TO_CHAR(date,'format_model')
格式:
SELECT TO_CHAR(SYSDATE, 'yyyy-mm-dd hh:mi:ss') FROM dual; -- 2022-01-13 09:03:51
日期格式的元素
YYYY | 2000 |
YEAR | TWO THOUSAND |
MM | 0 |
MONTH | JULY |
MON | JUL |
DY | MON |
DAY | MONDAY |
DD | 02 |
日期格式的元素
HH24:MI:SS AM | 15:45:32 PM |
DD "OF"< MONTH/td> | 12 OF OCTOBER |
to_char对日期的转换
SELECT * FROM EMP WHERE TO_CHAR(HIREDATE,'YYYY-MM-DD')='1980-12-17';
TO_DATE对字符的转换
to_date(char,'format_model');
to_date('2022年01月13日21:29:00','yyyy"年"mm"月"dd"日"hh:mi:ss') from dual ;
SELECT to_date('2022年01月13日 1:29:33','yyyy"年"mm"月"dd"日"hh:mi:ss') from dual ; 2022/1/13 1:29:33
TO_DATE对数字的转换
下面是在TO_CHAR 函数中经常使用的几种格式
9 | 数字 |
0 | 零 |
$ | 美元符 |
L | 本地货币符号 |
. | 小数点 |
, | 千位符 |
DAY | MONDAY |
DD | 02 |
案例说明
SELECT to_char(sal, '$99,999.00') FROM emp; -- $1,250.00
通用函数
NVL(exp1,expr2)
nvl2(expr1,expr2,expr3)
nullif(expr1,expr2)
coalesce(expr1,expr2,…)
-- 通用函数
/**
* NVL:将空值转换成一个已知的值
* 如果oracle第一个参数为空那么显示第二个参数的值,如果第一个参数的值不为空,则显示第一个参数本来的值。
* NVL(EXPR1,EXPR2)
**/
SELECT NVL('第一个参数不为空的值v1','第一个参数空的时候值v2') FROM DUAL;
/**
* NVL2(EXPR1,EXPR2,EXPR3)
* 如果该函数的第一个参数为空那么显示第二个参数的值,如果第一个参数的值不为空,则显示第三个参数的值
**/
SELECT NVL2('',1,2) FROM DUAL; -- 2
/**
* NULLIF(EXPR1,EXPR2)
* 作用:如果expr1和expr2相等返回null,否则返回第一个值
**/
SELECT NULLIF(1,2) FROM DUAL; -- 1
/**
* COALESCE(EXPR1,V1,...VN)
* EXPR1:为待检测的表达式,而其后的参数个数不定。
* 返回值:包括EXPR1在内的所有参数中的第一个非空表达式
**/
SELECT COALESCE(NULL,3,4,5) FROM DUAL;
-- 简单case表达式
SELECT job,
CASE JOB
WHEN 'CLERK' THEN
'clerk'
WHEN 'SALESMAN' THEN
'salesman'
ELSE
'其他'
END
FROM EMP;
-- 搜索case表达式
SELECT JOB, CASE
WHEN JOB = 'CLERK' THEN
'职员'
WHEN JOB = 'SALESMAN' THEN
'推销员'
ELSE
'马会计'
END
FROM emp;
注意事项
虽然这一点无需多言,但这里还是要强调一下:一定要注意 CASE 表达式里各个分支返回的数据类型是否一致。某个分支返回字符型,而其他分支返回数值型的写法是不正确的。
使用 CASE 表达式的时候,最容易出现的语法错误是忘记写 END 。虽然忘记写时程序会返回比较容易理解的错误消息,不算多么致命的错误。但是,感觉自己写得没问题,而执行时却出错的情况大多是由这个原因引起的,所以请一定注意一下。
与 END 不同,ELSE 子句是可选的,不写也不会出错。不写 ELSE 子句时,CASE 表达式的执行结果是 NULL 。但是不写可能会造成"语法没有错误,结果却不对"这种不易追查原因的麻烦,所以最好明确地写上 ELSE 子句(即便是在结果可以为 NULL 的情况下)。养成这样的习惯后,我们从代码上就可以清楚地看到这种条件下会生成 NULL,而且将来代码有修改时也能减少失误
-- decode函数的两种形式
-- 第一种格式
-- DECODE(EXPR,V1,R1,V2,R2...VN,RN,DEFAULT)
/**
* IF 条件=V1 THEN R1
* ELSIF 条件=v2 THEN R2
* ELSIF 条件=VN THEN RN
* ELSE RD(缺省值)
* END IF
**/
-- 当JOB='CLERK',返回值1
-- 当JOB='SALESMAN',返回值2
-- 当JOB='MANAGER',返回值3
SELECT EMPNO,
ENAME,
JOB,
DECODE(JOB, 'CLERK', 1, 'SALESMAN', 2, 'MANAGER', 3) NEW_JOB
FROM EMP;
-- 判断表中sal大小根据大小划分不同范围
SELECT * FROM emp;
SELECT DECODE(SIGN(), 1,) FROM emp;
-- 第二种格式
-- DECODE(字段或者字段运算,V1,V2,V3)
-- 这个函数运行的结果是,当字段或者字段的运算的值等于值1时,该函数返回值2,否则返回值3
-- 当然v1,v2,v3也可以是表达式,这个函数使得SQL语句简单了许多
-- 比较大小
-- SIGN(100-90)表达式值等于-1时候,返回100,否则90
SELECT DECODE(SIGN(100 - 90), -1, 100, 90) FROM DUAL;
-- 使用表达式来搜索字符串
SELECT DECODE(INSTR('ACM', 'C'), 0, '不含有C', '含有C') FROM DUAL; -- 含有C
-- 实现行列转换
-- decode相当于:case when then else end语句
SELECT DECODE(JOB, 'CLERK', ENAME, 0) ENAME_1,
DECODE(JOB, 'SALESMAN', ENAME, 0) ENAME_2,
DECODE(JOB, 'MANAGER', ENAME, 0) ENAME_3
FROM emp;
SELECT * FROM emp;
-- 创建表,插入数据,查询
CREATE TABLE t_decode(id INTEGER, NAME VARCHAR2(10));
-- 插入数据
INSERT INTO t_decode VALUES (1, 'a');
INSERT INTO t_decode VALUES (2, 'b');
INSERT INTO t_decode VALUES (3, 'c');
INSERT INTO t_decode VALUES (4, 'a');
SELECT * FROM T_DECODE;
SELECT decode(NAME, 'a', id, 0) id_1,
decode(NAME, 'b', id, 0) id_2,
decode(NAME, 'c', id, 0) id_3
FROM t_decode;
使用等值和不等值连接在SELECT语句中查询多个表中的数据
使用自连接
使用外连接查询不满足连接条件的数据
从多个表中获取数据
内连接查询操作列出与连接条件匹配的数据行,它使用比较运算符比较被连接列的列值。
区分重复的列名
SELECT * FROM EMP E, DEPT D WHERE EMP.DEPTNO = DEPT.DEPTNO;
连接多个表
连接n个表,至少需要n-1个连接条件
SELECT S.STU_ID, S.STU_NAME, S1.S_SCORE, SC.CLASS_NAME
FROM STUDENT S, SCORE S1, STU_CLASS SC
WHERE S.STU_ID = S1.STU_ID
AND S1.CLASS_ID = SC.CLASS_ID;
等值连接
等值连接:在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复属性。
-- ,形式 and
SELECT S.STU_ID, S.STU_NAME, S1.S_SCORE, SC.CLASS_NAME
FROM STUDENT S, SCORE S1, STU_CLASS SC
WHERE S.STU_ID = S1.STU_ID
AND S1.CLASS_ID = SC.CLASS_ID;
-- INNER JOIN ON
SELECT S.STU_ID, S.STU_NAME, S1.S_SCORE, SC.CLASS_NAME
FROM STUDENT S
INNER JOIN SCORE S1
ON S.STU_ID = S1.STU_ID
INNER JOIN STU_CLASS SC
ON S1.CLASS_ID = SC.CLASS_ID;
非等值连接
不等连接: 在连接条件使用除等于运算符以外的其它比较运算符比较被连接的 列的列值。这些运算符包括>、>=、<=、<、!>、!<和<>。
内连接和外连接
内连接:合并具有同一列的两个以上的表的行,结果集中不包含一个表与另一个表不匹配的行
外连接:两个表在连接过程中除了返回满足连接条件的行之外还需要返回左表或者右表不满足条件的行,这种连接叫做左(右)外连接,没有匹配的行时候,结果表中响应的列为null,外连接的where子句条件类似于内部连接,但是连接条件中没有匹配行的表的列后面需要加上外连接运算符,即 用圆括号括起来的加号。
对应SQL:LEFT/RIGHT/FULL OUTER JOIN。 通常省略OUTER关键字, 写成:LEFT/RIGHT/FULL JOIN。
在左连接和右连接时都会以一张A表为基础表,该表的内容会全部显示,然后加上A表和B表匹配的内容。 如果A表的数据在B表中没有记录。 那么在相关联的结果集行中列显示为空值(NULL)
对于外连接, 也可以使用“(+) ”来表示。 关于使用(+)的一些注意事项
该操作符只能出现在WHERE子句中,并且不能和OURTER JOIN语法同时使用
使用该操作符执行外连接时候,如果WHERE子句包含多个条件,必须在所有条件都包含+操作符
操作符只适用于列,不能用在表达式
操作符不能和OR,IN一起使用
操作符只能用于左外连接和右外连接,不能用于全外连接
LEFT JOIN是以左表的记录为基础的,示例中t_A可以看成左表,t_B可以看成右表,它的结果集是t_A表中的全部数据,再加上t_A表和t_B表匹配后的数据。换句话说,左表(t_A)的记录将会全部表示出来,而右表(t_B)只会显示符合搜索条件的记录。t_B表记录不足的地方均为NULL。
语法
-- + 方式
SELECT T1,COLUMN , T2.COLUMN FROM T1,T2 WHERE T1.COLUMN=T2.COLUN(+);
-- LEFT OUTER JOIN 方式
SELECT T1,COLUMN , T2.COLUMN FROM T1 LEFT OUTER JOIN T2 ON T1.COLUMN = T2.COLUMN;
举例说明
-- 返回右表不满足条件的数据
-- 方式1 +
SELECT * FROM STUDENT S1, SCORE S2 WHERE S1.STU_ID = S2.STU_ID(+);
-- 方式2 LEFT OUTER JOIN
SELECT *
FROM STUDENT S1
LEFT OUTER JOIN SCORE S2
ON S1.STU_ID = S2.STU_ID;
和LEFT JOIN的结果刚好相反,是以右表(SCORE)为基础的。它的结果集是STUDENT表所有记录,再加上SCORE和STUDENT匹配后的数据。STUDENT表记录不足的地方均为NULL。
语法
-- + 方式
SELECT T1,COLUMN , T2.COLUMN FROM T1,T2 WHERE T1.COLUMN(+)=T2.COLUN;
-- LEFT OUTER JOIN 方式
SELECT T1,COLUMN , T2.COLUMN FROM T1 RIGHT OUTER JOIN T2 ON T1.COLUMN = T2.COLUMN;
用(+)来实现, 这个+号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配表。如果加号写在左表,右表就是全部显示,所以是右连接
举例说明
-- 方式1 +
SELECT * FROM STUDENT S1, SCORE S2 WHERE S1.STU_ID(+)= S2.STU_ID;
-- 方式2 RIGHT OUTER JOIN
SELECT *
FROM STUDENT S1
RIGHT OUTER JOIN SCORE S2
ON S1.STU_ID = S2.STU_ID;
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值
-- FULL JOIN
SELECT * FROM STUDENT S1 FULL JOIN SCORE S2 ON S1.STU_ID = S2.STU_ID;
-- FULL OUTER JOIN
SELECT * FROM STUDENT S1 FULL OUTER JOIN SCORE S2 ON S1.STU_ID = S2.STU_ID;
自然连接时在两张表中寻找那些数据类型 和列名都相等的字段,然后自动地将他们连接起来
自然连接,自动匹配同名的列,虽然很方便,不用指定匹配的列
但也有缺点,虽然可以指定查询结果包括哪些列,但不能人为地指定哪些列被匹配,而内连接就可以自由指定
通过本次学习,可以知道
什么是分组函数
分组函数作用于一组数据,并对一组数据返回一个值
组函数类型
AVG | 平均值 |
COUNT | 计数 |
MAX | 最大值 |
MIN | 最小值 |
SUM | 求和 |
AVG()平均值和SUM()求和函数
SELECT AVG(SAL) FROM EMP; -- 平均值
SELECT SUM(SAL) FROM EMP; -- 求和
MIN(最小值)和 MAX(最大值)函数
-- MAX,MIN
SELECT MAX(SAL) MAX_VALUE,MIN(SAL) MIN_VALUE FROM EMP;
COUNT(计数)函数
-- COUNT(*)
SELECT COUNT(*) FROM EMP WHERE DEPTNO = 20 ;
-- 为空时候
SELECT COUNT(COMM) FROM emp;
组函数与空值
SELECT SUM(COMM),COUNT(*),AVG(COMM) FROM EMP;
原始表中有14条数据,结果看见avg(comm)只对非NULL的数据进行平均操作,那是因为oracle的组函数不会将null的数据进行忽略,如果需要实现对14个人取平均怎么办?
只需要对comm进行nvl操作,将null转换为0,那么组函数就能将这些null数据纳入统计范围了
在组函数中使用NVL函数
SELECT SUM(COMM),COUNT(*),AVG(NVL(COMM,0)) FROM EMP;
DISTINCT 关键字
SELECT DISTINCT(DEPTNO) FROM EMP;
分组数据: GROUP BY 子句语法
WHERE一定放在FROM后面
-- WHERE一定放在FROM后面
SELECT * FROM emp WHERE deptno IN(10,20,30);
在SELECT列表中所有未包含在组函数中的列都应该包含在GROUP BY 子句中
-- 错误示范
SELECT ENAME, DEPTNO FROM EMP GROUP BY DEPTNO;
-- 正确示范
SELECT DEPTNO ,COUNT(DEPTNO)FROM EMP GROUP BY DEPTNO;
包含在 GROUP BY 子句中的列不必包含在SELECT 列表中
-- 包含在 GROUP BY 子句中的列不必包含在SELECT 列表中
SELECT AVG(sal) FROM emp GROUP BY deptno;
使用多个列分组
-- 多个列分组
SELECT deptno,empno,AVG(sal) FROM emp GROUP BY deptno,empno;
可以在 HAVING 子句中使用组函数
-- 可以在 HAVING 子句中使用组函数
SELECT deptno,AVG(sal) FROM emp HAVING AVG(sal) > 500 GROUP BY deptno;
不能在 WHERE 子句中使用组函数
可以在order by 子句中使用组函数
-- 可以在order by 子句中使用组函数
SELECT deptno, AVG(sal)
FROM emp
HAVING AVG(sal) > 500
GROUP BY deptno
ORDER BY AVG(sal);
非法使用组函数
-- 非法使用组函数
-- 所有包含于SELECT 列表中,而未包含于组函数中的列都必须包含于 GROUP BY 子句中
-- 错误提示:ORA-00937:不是单组分组函数 ,group by 缺少列
SELECT deptno, COUNT(deptno) FROM emp;
-- 不能在 WHERE 子句中使用组函数
-- 错误提示:ORA-00934:此处不允许使用分组函数
SELECT deptno, AVG(sal) FROM emp WHERE AVG(sal) > 500 GROUP BY deptno;
-- 可以在 HAVING 子句中使用组函数
SELECT deptno, AVG(sal)
FROM emp
HAVING AVG(sal) > 500
GROUP BY deptno;
过滤分组:HAVING 子句
使用HAVING过滤分组
SELECT COLUMN,GROUP_FUNCTION
FROM TABLE
WHERE CONDITION
GROUP BY GROUP_BY_EXPRESSION
HAVING GROUP_CONDITION
ORDER BY COLUMN;
简单使用HAVING
-- 简单使用HAVING
SELECT DEPTNO,AVG(SAL) FROM EMP GROUP BY DEPTNO HAVING MAX(SAL) > 500 ;
嵌套组函数
-- 求出平均工资最高的部门编号,部门名称,部门平均工资
SELECT d.deptno, d.dname, e.sal
FROM (SELECT AVG(sal) sal, deptno
FROM emp e
GROUP BY deptno
HAVING AVG(sal) = (SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno)) e
LEFT JOIN dept d
ON e.deptno = d.deptno;
目标
谁的工资比BLAKE高
SELECT SELECT_LIST FROM TABLE WHERE EXPR OPERATOR(SELECT SELECT_LIST FROM TABLE)
-- 谁的工资比BLAKE高
SELECT ename,sal
FROM emp
WHERE sal >= (SELECT sal FROM emp WHERE ename = 'BLAKE');
注意事项
子查询要包含在括号内
将子查询放在比较条件的右侧
单行操作符对应单行子查询,多行操作符对饮多行子查询
单行子查询:从子查询中返回一行结果的查询
多行子查询:从子查询中返回多行结果的查询
操作符 | 含义 |
= | Equal to |
> | Greater than |
>= | Greater than or equal to |
< | Less than |
<> | Not equal to |
-- 子查询解决的问题
-- 谁的工资比BLAKE高
SELECT * FROM EMP;
-- 子查询的基本语法
SELECT SELECT_LIST
FROM TABLE
WHERE EXPR OPERATOR (SELECT SELECT_LIST FROM TABLE);
-- 基本使用
SELECT ENAME, SAL
FROM EMP
WHERE SAL >= (SELECT SAL FROM EMP WHERE ENAME = 'BLAKE');
-- 执行单行子查询
-- 返回JOB和7654号员工相同,SAL比7654号员工多的员工姓名,JOB和工资
SELECT ename, job, sal
FROM emp
WHERE job = (SELECT job FROM emp WHERE empno = 7369)
AND sal > (SELECT sal FROM emp WHERE empno = 7369);
-- 子查询中使用组函数
-- 返回公司工资最少的员工的name,job和sal
SELECT ename, job, sal FROM emp WHERE sal = (SELECT MIN(sal) FROM emp);
-- 子查询中使用HAVING
-- 首先执行子查询
-- 向主查询中HAVING子句中返回结果
-- 题目:查询最低工资大于10号部门最低工资的deptno和其最低工资
SELECT deptno, MIN(sal)
FROM emp
GROUP BY deptno
HAVING MIN(sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 20);
-- 非法使用子查询
SELECT deptno, ename
FROM emp
WHERE sal = (SELECT MIN(sal) FROM emp GROUP BY deptno);
/**
* ERROR at line 4:
* ORA-01427: single-row subquery returns more than
* one row
**/
-- 子查询中空值问题
SELECT deptno, MIN(sal)
FROM emp
GROUP BY deptno
HAVING MIN(sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 10);
操作符 | 含义 |
IN | 等于列表中任意一个 |
ANY | 和子查询返回的某一个值比较 |
ALL | 和子查询返回的所有值比较 |
-- 查询工资低于任何一个“CLERK”岗位的工资的雇员信息
SELECT SAL FROM EMP WHERE JOB = 'CLERK';
SELECT MAX(SAL) FROM EMP WHERE JOB = 'CLERK';
SELECT *
FROM EMP
WHERE SAL < (SELECT MAX(SAL) FROM EMP WHERE JOB = 'CLERK');
SELECT * FROM EMP;
SELECT *
FROM EMP
WHERE SAL < ANY (SELECT SAL FROM EMP WHERE JOB = 'CLERK');
--查询工资比所有的'SALESMAN'职位都高的雇员的编号,名字和工资
--[1]'SALESMAN'工资都是多少?
SELECT SAL FROM EMP WHERE JOB = 'SALESMAN';
SELECT EMPNO, ENAME, SAL
FROM EMP
WHERE SAL > ALL (SELECT SAL FROM EMP WHERE JOB = 'SALESMAN');
--查询部门20中的职务同部门10的雇员一样的雇员信息.
--[2]部门10是什么职务
SELECT JOB FROM EMP WHERE DEPTNO = 10;
SELECT *
FROM EMP
WHERE JOB IN (SELECT JOB FROM EMP WHERE DEPTNO = 10)
AND DEPTNO = 20;
该章节学习之后,我们可以
对象 | 描述 |
表 | 基本的数据存储集合,由行和列组成 |
视图 | 从表中抽出的逻辑上相关的数据集合 |
序列 | 提供有规律的数值 |
索引 | 提高查询效率 |
同义词 | 给对象起别名 |
表名和列名:
-- 创建表
CREATE TABLE ddept(deptno NUMBER(23), dname VARCHAR2(22), loc VARCHAR2(22));
SELECT * FROM ddept;
数据类型 | 描述 |
varchar2(size) | 可变长字符数据 |
char(size) | 定长字符数据 |
number | 可变长数值数据 |
date | 日期类型 |
long | 可变长字符数据 |
clob | 字符数据 |
blob | 二进制数据 |
rowid | 行地址 |
-- 语句:
CREATE TABLE tablename[(column1,column2,column3.....] AS subquery;
例子:
1.create table tabletest as select * from emp where 1=2;
这句话后面的where条件为假,表示只复制表的结构,而不复制数据,当where表后面的条件为真的时候,表示结构和表都复制过去。
2.create table emp20 as select * from emp where deptno=20;
这句话表示会将表的结构以及部门为20号的员工的信息复制过来。
修改列
alter table dept modify (last_name varchar2(30));
alter table dept modify (last_name varchar2(30) default '来来来');
-- 对默认值的修改只影响今后对表的修改
追加列
alter table dept add (job_id varchar2(10));
删除列
alter table dept drop column job_id;
重命名列
alter table dept rename column job_id to id ;
case end语法
SELECT
CASE
WHEN math>100 THEN '优'
WHEN math>90 THEN '良'
WHEN math>80 THEN '中'
WHEN math>70 THEN '及格'
WHEN math IS NULL THEN '缺考'
ELSE '不及格'
END
FROM
Person;
SELECT COUNT(order_num),
SUM(CASE
WHEN item_price > 3 THEN
1
ELSE
0
END)
FROM orderitems;
/* DECODE方法*/
SELECT COUNT(order_num), SUM(DECODE(1, item_price, 0)) FROM orderitems;
-- 判断字符串
-- 说明:字段empno如果是7014返回1,如果是7015返回2
SELECT empno, ename, COUNT(DECODE(empno, '7014', 1, '7015', 2)) FROM emp;
-- 函数分段
--(负无穷,2)
-- [2,4)
-- [4,+无穷)
SELECT * FROM t_decode;
SELECT ID,
NAME,
DECODE(SIGN(ID - 4),
1,
'high id',
0,
'high id',
'-1',
DECODE(SIGN(ID - 2), 1, 'mid id', 0, 'mid id', -1, 'low id'))
FROM t_decode
FOR UPDATE;
-- 比较大小
SELECT DECODE(SIGN(100 - 90), -1, 100, 90) FROM dual;
-- 表达式搜索字符串
SELECT ID, NAME, DECODE(INSTR(NAME, 'a'), 0, '不含有a', '含有a')
FROM t_decode;
-- 行列转换
SELECT DECODE(JOB, 'CLERK', ENAME, 0) ENAME_1,
DECODE(JOB, 'SALESMAN', ENAME, 0) ENAME_2,
DECODE(JOB, 'MANAGER', ENAME, 0) ENAME_3
FROM emp;