note: 执行命令是不需要分号(;)的,sql语句需要
eg:
hr@OCPDB> desc employees --执行命令不需要;
hr@OCPDB> select * from t_ocp; --执行sql语句需要 ;
show user --查看当前用户
select * from all_tables where owner='HR'; --查询某个用户下的所有表
select table_name from user_tables; --查看当前登录的用户的表
select * from all_tab_columns where table_name = 'EMPLOYEES';
select * from user_tables where table_name = 'EMPLOYEES';
create table hr.t_emp as select employee_id,last_name,department_id from hr.employees where department_id=50 or department_id is null; --根据其他表建表
远程连接 sqlplus hr/[email protected]:1521/ocpdb
1. DEFINE / VERIFY
1.1 DEFINE
sys@OCPDB> def AA=123
sys@OCPDB> select &AA from dual;
old 1: select &AA from dual
new 1: select 123 from dual
123
----------
123
1.2 VERIFY
sys@OCPDB> show ver
verify ON
sys@OCPDB> set ver off --将ver关闭,查询时不会显示old和new
sys@OCPDB> select &AA from dual;
123
----------
123
1.3 & and &&
sys@OCPDB> select &T from dual;
Enter value for t: 123
123
----------
123
sys@OCPDB> select &T from dual; -- 一个& 不会保存值,下一次还会需要输入
Enter value for t: 234
234
----------
234
sys@OCPDB> select &&Y from dual; -- 两个&&(Double-Ampersand Substitution) 会保存值,下一次不需要输入
Enter value for y: 345
345
----------
345
sys@OCPDB> select &&Y from dual;
345
----------
345
sys@OCPDB> select &Y from dual;
345
----------
345
2. 脚本执行顺序
hr@OCPDB> select * from employees where employee_id=100;
(1)from employees
(2)where employee_id=100
(3)select *
3.字段别名,对于特殊字符用双引号
hr@OCPDB> select employee_id "$ID" from employees where rownum = 1;
$ID
----------
100
4.Q操作符,可处理特殊字符,双引号不行 q'[ ]'
hr@OCPDB> select department_name || q'[ Department's Manager Id: ]' || manager_id as "Department and Manager" from departments where rownum=1;
Department and Manager
------------------------------------------------------------------------------------------------
Administration Department's Manager Id: 200
对比:
hr@OCPDB> select department_name || ' Department' || '''' || 's Manager Id: ' || manager_id as "Department and Manager" from departments where rownum=1;
Department and Manager
------------------------------------------------------------------------------------------------
Administration Department's Manager Id: 200
hr@OCPDB> select q'[123$%'''']' name from dual;
NAME
---------
123$%''''
5. operators 操作符
5.1
hr@OCPDB> select last_name, salary, salary+30 from employees where rownum<=10;
LAST_NAME SALARY SALARY+30
---------- ---------- ----------
OConnell 2600 2630
Grant 2600 2630
Whalen 4400 4430
Hartstein 13000 13030
Fay 6000 6030
Mavris 6500 6530
Baer 10000 10030
Higgins 12008 12038
Gietz 8300 8330
King 24000 24030
5.2
hr@OCPDB> select sysdate+2 from dual; --加两天
SYSDATE+2
---------
28-MAR-21
hr@OCPDB> select sysdate*2 from dual; --日期不能相乘
select sysdate*2 from dual
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got DATE
hr@OCPDB> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
hr@OCPDB> select sysdate+1/24 from dual; --加一个小时
SYSDATE+1/24
-------------------
2021-03-26 22:56:54
6. || 连接符
hr@OCPDB> select 'aa'||'bb' from dual;
'AA'
----
aabb
hr@OCPDB> select DEPARTMENT_ID || ' ' || MANAGER_ID from departments where rownum < 10;
DEPARTMENT_ID||''||MANAGER_ID
----------------------------------------------------------------------------------
10 200
20 201
30 114
40 203
50 121
60 103
70 204
80 145
90 100
9 rows selected.
7. 去重(duplicate),distinct要放在最前面
hr@OCPDB> SELECT distinct department_id from departments;
hr@OCPDB> select MANAGER_ID, distinct DEPARTMENT_ID from departments; --error
select MANAGER_ID, distinct DEPARTMENT_ID from departments
*
ERROR at line 1:
ORA-00936: missing expression
8. desc
hr@OCPDB> desc employees
9.隐式转换(string to date)
hr@OCPDB> select last_name from employees where hire_date = '17-OCT-03';
LAST_NAME
----------
Rajs
10. 输出执行计划
hr@OCPDB> set autotrace traceonly
SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is enabled
SP2-0611: Error enabling STATISTICS report
hr@OCPDB> select last_name from employees where hire_date = '17-OCT-03';
Execution Plan
----------------------------------------------------------
Plan hash value: 1445457117
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 1 | 16 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("HIRE_DATE"='17-OCT-03')
hr@OCPDB> set autotrace off
11. between .. and... [] 左右闭区间
hr@OCPDB> select EMPLOYEE_ID, MANAGER_ID from employees where EMPLOYEE_ID between 200 and 206;
EMPLOYEE_ID MANAGER_ID
----------- ----------
200 101
201 100
202 201
203 101
204 101
205 101
206 205
7 rows selected.
12. IN
hr@OCPDB> SELECT employee_id, last_name, salary, manager_id from employees where manager_id in (100, 101, 201);
等价于
hr@OCPDB> select employee_id, last_name, salary, manager_id from employees where manager_id = 100 or manager_id = 101 or manager_id = 201;
等价于(老师说union all的效率更高 ?)
select employee_id, last_name, salary, manager_id from employees where manager_id = 100
union all
select employee_id, last_name, salary, manager_id from employees where manager_id = 101
union all
select employee_id, last_name, salary, manager_id from employees where manager_id = 201;
13. like(大小写敏感)
select first_name from employees where first_name like 'S%';
select last_name from employees where last_name like '_o%'; -- _表示匹配一个任意字符
14. NULL
select * from employees where manager_id not in (select manager_id from employees where employee_id = 100); --子查询为 null, 父查询也为空, 与常规理解不同
select * from employees where manager_id = null; -- 错误,这样会无结果,对于null,应该用is
select * from employees where manager_id is null;
15. 操作符(AND OR NOT)
and和or的优先级
select * from employees where manager_id = 101 or manager_id = 103 and employee_id = 104; (and的优先级高于or,即等价于)
等价于
select * from employees where manager_id = 101 or (manager_id = 103 and employee_id = 104);
算数符(Arithmetic operators) > 连接符(Concatenation operator) > 比较符(Comparison conditions) > IS [NOT] NULL, LIKE, [NOT] IN > [NOT] BETWEEN > 不等于(Not equal to) > NOT logical operator > AND logical operator > OR logical operator
16. 排序(order by)
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by employee_id; -- 默认升序,由小到大
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by emp_id; -- 用别名排序
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by 1; -- 对第一列进行排序
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by 1, manager_id; -- 先对第一列排序,再对manager_id 排序, Null值排在最后,null相当于最大值
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by manager_id nulls first; --将null值排在最前面
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by manager_id nulls last;
hr@OCPDB> select employee_id as emp_id, last_name, manager_id from employees order by manager_id desc nulls last; -- 降序排序
17. fetch first 限定输出比例
hr@OCPDB> create table T_OCP(id int, name varchar2(32));
hr@OCPDB> insert into t_ocp values(1, 'OCP1');
hr@OCPDB> insert into t_ocp values(2, 'OCP2');
hr@OCPDB> insert into t_ocp values(3, 'OCP3');
hr@OCPDB> insert into t_ocp values(4, 'OCP4');
hr@OCPDB> insert into t_ocp values(5, 'OCP5');
hr@OCPDB> insert into t_ocp values(6, 'OCP6');
hr@OCPDB> insert into t_ocp values(7, 'OCP7');
hr@OCPDB> insert into t_ocp values(8, 'OCP8');
hr@OCPDB> commit;
select id, name from t_ocp ORDER BY id FETCH first 50 percent rows ONLY; --只输出前50%行,4行
hr@OCPDB> insert into t_ocp values(4, 'OCP4');
hr@OCPDB> insert into t_ocp values(4, 'OCP4');
hr@OCPDB> commit;
select id, name from t_ocp ORDER BY id FETCH first 50 percent row WITH TIES; -- 输出临界值,id=4的有三行,总共6行
18. 变量
(1) VIRIABLE
hr@OCPDB> var ID number
hr@OCPDB> select * from t_ocp where id = &ID; -- 一个&, 值不会保留
Enter value for id: 1
old 1: select * from t_ocp where id = &ID
new 1: select * from t_ocp where id = 1
ID NAME
---------- --------------------------------
1 OCP1
hr@OCPDB> select * from t_ocp where id = &&ID; -- 两个取地址符,值会保留
Enter value for id: 3
old 1: select * from t_ocp where id = &&ID
new 1: select * from t_ocp where id = 3
ID NAME
---------- --------------------------------
3 OCP3
(2) DEFINE
(3) VERIFY
19. 单行函数(single-row functions: return one result per row)
(1) character(字符型)
case-conversion functions: LOWER/UPPER/INITCAP
character-manipulation functons: CONCAT/SUBSTR/LENGTH/INSTR/LPAD | RPAD/TRIM/REPLACE
hr@OCPDB> select first_name, lower(first_name) from employees where rownum <=2;
LENGTH: 统计的是字符长度,不是字节长度,GBK字符集里面,一个中文占两个字节,在utf8字符集下,一个中文占三个字节
字符 字节 比特位
a 1 1111 1111(8位)
你(GBK) 2 1111 1111 1111 1111(16位)
你(UTF) 3 24位
hr@OCPDB> create table t_t(id int, name varchar2(32), addr nvarchar2(32)); -- varchar2 标准字符集下的,GBK,即NLS_CHARACTERSET。 nvarchar2 国家字符集下的,即NLS_NCHAR_CHARACTERSET
hr@OCPDB> insert into t_t values(1, '小明', '西湖区');
hr@OCPDB> commit;
解决完字符编码问题以后
hr@OCPDB> truncate table t_t; --清空表t_t
hr@OCPDB> insert into t_t values(1, '小明', '西湖区');
hr@OCPDB> select name, lengthb(name), addr, lengthb(addr) from t_t;
hr@OCPDB> insert into t_ocp values(3, '你好');
hr@OCPDB> select name, length(name), lengthb(name) from t_ocp;
sys@OCPDB> select concat('hello',' world') from dual; --hello world, 只能拼接两个字符串
select substr('helloworld', 1, 3) from dual; -- hel, 从第一位开始截取,截取三位
select substr('helloworld', -3, 1) from dual; -- r, 从倒数第三个开始,取一位
hr@OCPDB> select lpad('hello', 10, '*') from dual; -- *****hello 期望显示10位,不够10位左边填充*
hr@OCPDB> select rpad('hello', 10, '*') from dual; -- hello***** 期望显示10位,不够10位右边填充*
(2) Number(数字型)
-- round 和 trunc
hr@OCPDB> select round('12345.678', 2) from dual; --12345.68,四舍五入,保留两位小数
hr@OCPDB> select round('45678.123',-2) from dual; --45700,从小数点往左数两位
hr@OCPDB> select round('45678.123', -1) from dual; --45680
hr@OCPDB> select trunc('12345.678',2) from dual; --12345.67,保留两位小数,不做四舍五入
hr@OCPDB> select trunc('45678.123',-2) from dual; --45600,从小数点往左开始截取
--ceil和floor
hr@OCPDB> select ceil(1234.45) from dual; -- 1235,比1234.45大的最小的整数
hr@OCPDB> select ceil(-1234.45) from dual; -- -1234
hr@OCPDB> select floor(1234.45) from dual; -- 1234,比1234.45小的最大整数
hr@OCPDB> select floor(-1234.45) from dual; -- -1235,比 -1234.45小的最大整数
hr@OCPDB> select mod(8,3) from dual; -- 2,取余数
hr@OCPDB> select power(3,2) from dual; -- 9,平方,幂次函数
hr@OCPDB> select sqrt(64) from dual; -- 8,平方根
hr@OCPDB> select abs('-323') from dual; --323,取绝对值
(3) General(通用型)
(4) Conversion(转换型)
(5) Date(日期类型)
hr@OCPDB> select to_char(to_date('50-07-12','YY-MM-DD'), 'YYYY-MM-DD') from dual; -- 2050-07-12 YY格式表示本世纪
hr@OCPDB> select to_char(to_date('50-07-12','RR-MM-DD'), 'YYYY-MM-DD') from dual; -- 1950-07-12(上世纪) RR格式参见图片说明
hr@OCPDB> show parameter nls_date_format; -- error,查看数据库默认日期格式
hr@OCPDB> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
hr@OCPDB> select sysdate from dual;
ALTER SESSION SET TIME_ZONE = '-5:0';
hr@OCPDB> select SESSIONTIMEZONE, CURRENT_DATE from dual; -- +08:00 2021-04-05 20:22:31, CURRENT_DATE的时间与设置的time_zone有关,sysdate与系统时间有关
hr@OCPDB> select SESSIONTIMEZONE, CURRENT_TIMESTAMP from dual; --+08:00 05-APR-21 08.31.39.991837 PM +08:00, CURRENT_TIMESTAMP也与设置的time_zone有关
question:CURRENT_TIMESTAMP和LOCALTIMESTAMP的区别
hr@OCPDB> select CURRENT_TIMESTAMP, LOCALTIMESTAMP from dual; -- 会话级的函数,时间随time_zone改变
CURRENT_TIMESTAMP LOCALTIMESTAMP
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
05-APR-21 08.39.44.469577 PM +08:00 05-APR-21 08.39.44.469577 PM
hr@OCPDB> select SYSTIMESTAMP, SYSDATE, DBTIMEZONE from dual; -- 系统级的日期函数,时间不会随time_zone改变
SYSTIMESTAMP SYSDATE DBTIMEZONE
05-APR-21 08.48.56.795165 PM +08:00 2021-04-05 20:48:56 +00:00
日期运算:
hr@OCPDB> select last_name, (sysdate-hire_date)/7 AS weeks from employees where department_id = 90;
hr@OCPDB> select to_date('2021-03-03 12:00:00', 'YYYY-MM-DD HH24:MI:SS')-to_date('2021-01-03 18:00:00', 'YYYY-MM-DD HH24:MI:SS') from dual; --58.75
日期操作
hr@OCPDB> select MONTHS_BETWEEN(to_date('02-02-1995','MM-DD-YYYY'),to_date('01-01-1995','MM-DD-YYYY')) "Months" from dual; --1.03225806 前面减去后面的日期
hr@OCPDB> select hire_date,ADD_MONTHS(hire_date, 1) "Next month" FROM employees where last_name='Baer'; -- 加一个月
hr@OCPDB> select NEXT_DAY('2021-03-06', 'TUESDAY') "NEXT DAY" from dual; -- 2021-03-09 00:00:00 取下一个周二的时间
hr@OCPDB> select LAST_DAY('2021-03-15') from dual; -- 2021-03-31 00:00:00 取本月最后一天
hr@OCPDB> select SYSDATE, ROUND(SYSDATE, 'YEAR'), ROUND(SYSDATE, 'MONTH') from dual; -- 06-APR-21 01-JAN-21 01-APR-21,四舍五入
hr@OCPDB> select ROUND(to_date('2021-08-01','yyyy-mm-dd'), 'year') from dual; -- 01-JAN-22,四舍五入,下半年
hr@OCPDB> select ROUND(to_date('2021-03-21 10:46:00', 'yyyy-mm-dd HH24:mi:ss'), 'day') from dual; --- 21-MAR-21,一周七天做四舍五入,周日到周六为一周
hr@OCPDB> select ROUND(to_date('2021-03-17 10:46:00', 'yyyy-mm-dd HH24:mi:ss'), 'day') from dual; -- 14-MAR-21,3月17号为周三,取这一周的第一天
hr@OCPDB> select SYSDATE, trunc(SYSDATE, 'YEAR'), TRUNC(SYSDATE, 'MONTH') from dual; -- 06-APR-21 01-JAN-21 01-APR-21,直接截取
hr@OCPDB> select TRUNC(to_date('2021-03-25', 'yyyy-mm-dd'), 'MONTH') from dual; -- 01-MAR-21
hr@OCPDB> select TRUNC(SYSDATE, 'DAY') from dual; -- 04-APR-21,每周的第一天
20. 多行函数(multiple-row functions: return one result per set of rows, eg: count/max/min)
21. 中文乱码问题(根本原因是数据库的字符集和操作系统的字符集不一样)
[root@ocpdb ~]# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
hr@OCPDB> select * from nls_database_parameters; --查看数据库字符集
NLS_NCHAR_CHARACTERSET UTF8
NLS_CHARACTERSET ZHS16GBK
hr@OCPDB> select dump(name, 16) from t_t; --用16进制显示name,确认里面确实存的是?
DUMP(NAME,16)
Typ=1 Len=6: 3f,3f,3f,3f,3f,3f
NLS_LANG='SIMPLIFIED CHINESE_CHINA.ZHS16GBK' -- 告诉数据库当前客户端使用的字符集是什么,数据库在输出时决定需不需要转码
NLS_LANG = language_territory.charset
由三部分组成:
a. language
b. territory
c. charset
可通过v$nls_valid_values视图查询,例如
$export NLS_LANG='AMERICAN_AMERICA.UTF8'
hr@OCPDB> select * from v$nls_valid_values; --数据库里所有可用的语言,地区,字符集编码
解决步骤
(1)[oracle@ocpdb ~]$ vi .bash_profile
(2)add NLS_LANG
ORACLE_HOSTNAME=ocpdb
NLS_LANG='AMERICAN_AMERICA.UTF8'
#NLS_LANG='SIMPLIFIED CHINESE_CHINA.ZHS16GBK'
TNS_ADMIN=$ORACLE_HOME/network/admin
(3)[oracle@ocpdb ~]$ source .bash_profile
22.dual表,输出不一定是单行单列
hr@OCPDB> select level from dual connect by level <= 7; --层次查询,输出多行
23.隐式转换(Implicit Data Type Conversion)
hr@OCPDB> select '11'+1 from dual; -- 12
hr@OCPDB> select * from employees where employee_id = '100';
-- 数值转字符串
hr@OCPDB> create table t_t(ID varchar2(32));
hr@OCPDB> insert into t_t values('1');
hr@OCPDB> insert into t_t values('2');
hr@OCPDB> commit;
hr@OCPDB> select * from t_t where id=2;
-- 日期转字符串
hr@OCPDB> ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD';
hr@OCPDB> create table t_t(ID INT, NAME VARCHAR2(32), BIRTHDAY VARCHAR2(32));
hr@OCPDB> insert into t_t values(1, 'TOM', '1985-03-06');
hr@OCPDB> insert into t_t values(2, 'JACK', '1988-05-13');
hr@OCPDB> commit;
hr@OCPDB> select * from t_t where BIRTHDAY = TO_DATE('1985-03-06', 'YYYY-MM-DD');
-- 字符串转日期
hr@OCPDB> select employee_id, first_name, last_name from employees where hire_date='2005-09-28';
hr@OCPDB> select DATE '31-03-21' from dual; -- 0031-03-21,关键字DATE将字符串转成日期
24.显示转换(Explicit Data Type Conversion) to_number/to_date/to_char
(1) to_char
--日期转字符串
hr@OCPDB> select last_name, to_char(hire_date) as HIREDATE from employees;
hr@OCPDB> select last_name, to_char(hire_date, 'FMDD MONTH YYYY') AS HIREDATE from employees; --FM用于申明格式
hr@OCPDB> select last_name, to_char(hire_date, 'fmDD Month YYYY', 'NLS_DATE_LANGUAGE=AMERICAN') as HIREDATE from employees; --包含NLS_DATE_LANGUAGE选项
--数值转字符串
hr@OCPDB> select to_char(1023.99, '$9,999') as "Amount" from dual; -- $1,024
hr@OCPDB> select to_char(10235.99, '$9,999') as "Amount" from dual; --#######,格式位不对
hr@OCPDB> select to_char(10235.99, '$999,999') as "Amount" from dual; -- $10,236
hr@OCPDB> select to_char(10000, '99G999D99C', 'NLS_NUMERIC_CHARACTERS = '',.''NLS_ISO_CURRENCY=CHINA') "Amount" from dual; -- 10.000,00CNY
-- 字符串转字符串
hr@OCPDB> select to_char('abcd') from dual;
(2)to_number
-- 字符串转数值
hr@OCPDB> select to_number('-AusDollars100','L9G999D99', ' NLS_NUMERIC_CHARACTERS = '',.''NLS_CURRENCY = ''AusDollars''') "Amount" from dual; -- -100
(3)to_date函数
-- 字符串转日期
hr@OCPDB> select employee_id, first_name, last_name from employees where hire_date hr@OCPDB> select to_date('JANUARY 15, 1989, 11:00 A.M.', 'MONTH DD, YYYY, HH:MI A.M.', 'NLS_DATE_LANGUAGE=AMERICAN') from dual; --15-JAN-89 25.空值处理函数 hr@OCPDB> select nvl(123, '35') from dual; -- 123,如果第一个参数为空,取第二个参数,否则取第一个参数 hr@OCPDB> select last_name, nvl(to_char(commission_pct), 'Not Applicable') commission from employees where last_name like 'B%' order by last_name; hr@OCPDB> select nvl2(123, '456', '789') from dual; -- 456 如果第一个不为空,输出第二个参数,第一个为空,输出第三个参数 hr@OCPDB> select nullif(1,2) from dual; -- 判断是否相等,相等输出空值,不相等输出第一个值 26. 条件表达式 -- case表达式 select last_name, job_id, salary, case job_id when 'IT_PROG' then 1.10 * salary when 'ST_CLERK' then 1.15 * salary when 'SA_REP' then 1.2 * salary else salary end "REVISED_SALARY" from employees; select last_name, job_id, salary, case when job_id = 'IT_PROG' then 1.1 * salary when job_id = 'ST_CLERK' then 1.15 * salary when job_id = 'SA_REP' then 1.2 * salary else salary end 'REVISED_SALARY' from employees; -- decode函数 select last_name, job_id, salary, decode(job_id, 'IT_PROG', 1.10 * salary, 'ST_CLERK', 1.15 * salary, 'SA_REP', 1.20 * salary, salary) REVISED_SALARY from employees; 27. 一个@和两个@@的区别 两个@@可以在当前脚本中执行其他脚本 28.分组函数 hr@OCPDB> select AVG(salary), MAX(salary), MIN(salary), sum(salary) from employees where job_id like '%REP%'; -- null不会算在avg里 hr@OCPDB> select MIN(hire_date), MAX(hire_date) from employees; hr@OCPDB> select MIN(hire_date), MAX(hire_date) from employees; hr@OCPDB> select avg(commission_pct) from employees; -- null不会算在avg里 hr@OCPDB> select avg(nvl(commission_pct, 0)) from employees; hr@OCPDB> select count(1), count(department_id), count(distinct department_id) from employees; --count不算null,除非是统计总的,如count(1) 对比:having,对分组结果进行过滤 hr@OCPDB> select department_id, avg(salary) from employees where department_id in (100,120,122,123) having avg(salary) > 8000 group by department_id order by 1; -- 100 8601.33333 hr@OCPDB> select department_id, avg(salary) from employees where department_id in (100,120,122,123) group by department_id having avg(salary) > 8000 order by 1; -- 100 8601.33333 执行顺序 a. from b. where c. group by d. having e. order by hr@OCPDB> select department_id, job_id, sum(salary) from employees where department_id > 40 group by department_id, job_id order by department_id; 对比: hr@OCPDB> select MAX(AVG(salary)) from employees group by department_id; hr@OCPDB> select MAX(AVG(salary)) from employees; -- error 29.多表关联 hr@OCPDB> select employee_id, first_name, job_id, job_title from employees a natural join jobs b; --自然连接,相同字段自动做拼接,列名不能加表的别名 等价于 hr@OCPDB> select a.employee_id, a.first_name, b.job_id, b.job_title from employees a inner join jobs b on a.job_id = b.job_id; --共有列要指明是哪张表的 等价于 sys@OCPDB> select a.employee_id, a.first_name, job_id, b.job_title from hr.employees a inner join hr.jobs b using(job_id); -- job_id 共有列不能指明哪张表 sys@OCPDB> select e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id from hr.employees e join hr.departments d on (e.department_id=d.department_id) and e.manager_id = 149; 等价于 sys@OCPDB> select e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id from hr.employees e join hr.departments d on (e.department_id=d.department_id) where e.manager_id = 149; sys@OCPDB> select e.employee_id, e.last_name, e.department_id, d.location_id from hr.employees e where e.employee_id in (200, 201) join hr.departments d on (e.department_id=d.department_id); select e.employee_id, e.last_name, e.department_id, d.location_id from hr.emloyees e where e.employee_id in (200, 201) join hr.departments d on (e.department_id=d.department_id) ERROR at line 1: ORA-00933: SQL command not properly ended ---此语句报错,where应该在join后面 from A left (outer) join B,A表作为驱动表,展示A表的所有数据,B表只会展示和A表的交集部分 =+ select * from emp a, dept b where a.employee_id = b.employee_id(+); from A right join B,B表作为驱动表,展示B表的所有数据,A表只会展示和B表交集的部分 += select * from emp a, dept b where a.employee_id(+) = b.employee_id; from A full join B,展示A表和B表所有 cross join:笛卡尔积 A表 1 2 3 B表 4 5 A cross join B 1 4 1 5 2 4 2 5 3 4 3 5 select * from A cross join B; 30.self join(自关联) sys@OCPDB> select worker.last_name emp, manager.last_name mgr from hr.employees worker join hr.employees manager on (worker.manager_id = manager.employee_id); 31.nonequijoins(不等值关联:不相等的时候关联) hr@OCPDB> select e.last_name, e.salary, j.grade_level from hr.employees e JOIN hr.job_grades j on e.salary between j.lowest_sal and j.highest_sal; 32.单行子查询 hr@OCPDB> select * from employees where salary > (select avg(salary) from employees); SELECT last_name,job_id,salary FROM hr.employees WHERE job_id = ( SELECT job_id FROM hr.employees WHERE last_name = 'Popp' ) AND salary > ( SELECT salary FROM hr.employees WHERE last_name = 'Popp' ); select last_name, hire_date from hr.employees where hire_date>(select hire_date from hr.employees where last_name='Davies'); (1)from hr.employees (2)select hire_date from hr.employees where last_name='Davies' (3)where hire_date> hr@OCPDB> select last_name, job_id, salary from employees where (employee_id,manager_id)=(select employee_id,manager_id from employees where employee_id=103); select department_id, MIN(salary) from employees group by department_id having min(salary) > (select MIN(salary) from employees where department_id=30); 33.多行子查询 (ANY / ALL) select employee_id, last_name, job_id, salary from employees where salary < ANY(select salary from employees where job_id='IT_PROG') -- 比其中一个小就行,比最大值小 and job_id<>'IT_PROG'; select employee_id, last_name, job_id, salary from employees where salary < ALL(select salary from employees where job_id='IT_PROG') -- 比所有值小,比最小值小 and job_id<>'IT_PROG'; 34.set operators (1)UNION(去重)/UNION ALL(不会去重) create table hr.t_1(a int); insert into hr.t_1(a) values(1); insert into hr.t_1(a) values(2); insert into hr.t_1(a) values(3); insert into hr.t_1(a) values(null); commit; create table hr.t_2(a int); insert into hr.t_2(a) values(2); insert into hr.t_2(a) values(3); insert into hr.t_2(a) values(4); insert into hr.t_2(a) values(null); commit; select * from hr.t_1 union select * from hr.t_2; -- 1,2,3,4,null 空值包含 select * from hr.t_1 union all select * from hr.t_2 --1 2 3 null 2 3 4 null create table hr.t_emp as select employee_id,last_name,department_id from hr.employees where department_id=50 or department_id is null; --根据其他表建表 select employee_id as "EMP_ID", last_name, department_id from hr.employees union select employee_id as "EMPPP_ID", last_name, department_id from hr.t_emp; --取第一个的列名 (2)INTERSECT(取交集) select * from hr.t_1 intersect select * from hr.t_2 -- 2 3 null (3)A MINUS B(A-B,从A当中,把与B重合的部分去掉) select * from hr.t_1 minus select * from hr.t_2 -- 1 (4)ORDER BY子句 select employee_id as "EMP_ID", last_name, department_id from hr.employees union all select employee_id as "EMP_ID", last_name, department_id from hr.t_emp order by EMP_ID; --对总的结果进行排序 思考:前后结果集的字段类型是否需要保持一致 答案:ORA-01790: expression must have same datatype as corresponding expression,不行 35.DML语句(SELECT,UPDATE,INSERT,DELETE,MERGE INTO) write your insert statement with a subquery: insert into sales_reps(id, name, salary, commisson_pct) select employee_id, last_name, salary, commission_pct from employees where job_id like '%REP%' 更新成null值: update hr.t_emp set name=null where id=1; 更新两列: update hr.employees set (job_id,salary) = (select job_id,salary from hr.employees where employee_id = 205) where employee_id = 103; delete from hr.t_1 where a = 1; 等价于 delete hr.t_1 where a = 1; delete from hr.t_1; delete from hr.employees where department_id in (select department_id from hr.departments where department_name like '%Public%'); --ORA-02292: 违反完整约束条件 (HR.DEPT_MGR_FK) - 已找到子记录 36.DDL语句,数据定义语言(CREATE,DROP,TRUNCATE,ALTER) (1)number类型 create table hr.t_num(a number(6,2)); --6位长度,保留两位小数点,最大值9999.99 insert into hr.t_num values(1234.56); --可以存 insert into hr.t_num values(12.3456); --小于9999.99,可以存入,12.35,四舍五入 insert into hr.t_num values(123456); --不成功,超出最大精度 (2)日期类型 create table hr.t_date(a INTERVAL YEAR TO MONTH,b INTERVAL YEAR(3) TO MONTH,c INTERVAL DAY TO SECOND); insert into hr.t_date values(interval '12-3' year to month, interval '120-3' year(3) to month, '12 12:10:50.66'); --12年3个月, 120年3个月, 12天12小时..设定时间精度 commit; select * from hr.t_date; select last_name,EXTRACT(YEAR FROM (SYSDATE-hire_date) YEAR TO MONTH) || ' years ' || EXTRACT(MONTH FROM (SYSDATE-hire_date) YEAR TO MONTH) || ' months' "Interval" FROM hr.employees; --OConnell 13 years 10 months create table t_dept(deptno number(2), dname varchar2(14), loc varchar2(13), create_date DATE default SYSDATE); create table hr.t_y(id int,name varchar2(32 char), addr varchar2(32 byte)); create table hr.t_y(id int,name varchar2(32), addr varchar2(32 byte)) --不指定char还是byte的时候,根据参数nls_length_semantics设置 select * from v$parameter; sys@OCPDB> show parameter nls; drop table t_1 purge; (purge, 彻底删除,不会放到回收站里) truncate 和 delete的区别 truncate:产生的日志量很少,执行速度快,不能回滚,常规手段可用备份恢复,truncate之后,data_object_id会改变,重新分配段,所以无法回滚 select * from dba_objects where object_name='T_1', delete:可以通过日志回滚 SCN:system change number 37.DCL语句,控制语句(GRANT,REVOKE,COMMIT,ROLLBACK) create table hr.t_product(pcode NUMBER(2), pname VARCHAR2(20)); -- set trnsaction name 'update_1' --显示指定事务的开始 insert into hr.t_product values(1,'pen'); insert into hr.t_product values(2,'pencil'); insert into hr.t_product values(3, 'fountain pen'); savepoint a; --保存点,只在当前事务中有效 update hr.t_product set pcode=10 where pcode=1; commit; --commit之后保存点a失效 delete from hr.t_product where pcode=2; savepoint b; update hr.t_product set pcode=30 where pcode=3; savepoint c; delete from hr.t_product where pcode=10; rollback to savepoint b; commit; select * from hr.t_product 38.约束(including constraints:not null,unique,primary key,foreign key,check) (1)colmn-level constraint syntax(列级约束): create table hr.t_y( employee_id NUMBER(6) CONSTRAINT y_employee_id_pk PRIMARY KEY, first_name VARCHAR2(20), last_name VARCHAR2(20) ); -- primary key 糅合了not null 和unique的特性 (2)table-level contraint syntax(表级约束) create TABLE hr.t_y( employee_id NUMBER(6), first_name VARCHAR2(20), last_name VARCHAR2(20), CONSTRAINT y_employee_id_pk PRIMARY KEY (EMPLOYEE_ID) ); create table hr.t_y_temp as select * from hr.t_y where 1=0; --主键约束是否被继承到新表中? (3)外键约束 create table hr.t_class( id number not null, name varchar2(50), constraint PK_T_CLASS primary key (ID) ) create table hr.t_student( id number not null, name varchar2(50), class_id number, constraint PK_T_STUDENT primary key (ID), constraint FK_T_STUDENT_CLASS_ID foreign key (CLASS_ID) references hr.t_class (ID) --外键约束 ) 实验1: create table t(id int not null, name varchar2(32)); insert into t values(1, 'yyy'); commit; create table t2 as select * from t where 1=0; -- 1=0 创建空表,表结构一样,t2也有非空约束,非空约束传递 实验2 create table t(id int primary key, name varchar2(32)); insert into t values(1, 'yyy'); commit; create table t2 as select * from t where 1=0; --主键约束不会继承 select * from dba_constraints where owner ='HR' and table_name=''; --数据字典查看表column约束 39.删除一列 (1)alter drop alter table [table_name] drop ([column_name]); alter table t2 drop (name); (2)set unused(数据库并发量高的时候,对数据库影响小,数据库繁忙的时候,先把column置为不可用,再drop删掉) alter table [table_name] set unused ([column_name],[column_name]); or alter table [table_name] set unused column [column_name],[column_name]; --oracle里最多1000列,unused的列会占指标 alter table [table_name] drop unused columns; 40.read-only tables(将表设置为只读状态) alter table employees READ ONLY; alter table employees READ WRITE; SQL第二部分(80194) 数据字典 (1)user_xxx:当前用户拥有的对象 select * from user_tables; --当前用户创建的对象 (2)