Upload
kenny
View
166
Download
0
Embed Size (px)
DESCRIPTION
Oracle11g Database SQL 语言基础. 2011.8 By Kevinlin. 林少杰 [email protected]. SQL 语言简介. SQL 语言 (Structured Query Language) 是访问关系型数据库的标准语言。 SQL 语言可以分为五种类型: 查询 (QUERY) - SELECT 数据处理 (DML)- INSERT, UPDATE, DELETE 数据定义 (DDL) - CREATE, ALTER, DROP, RENAME, TRUNCATE - PowerPoint PPT Presentation
Citation preview
Oracle11g Database SQL 语言基础
2011.8ByKevinlin. 林少杰[email protected]
SQL 语言简介• SQL 语言 (Structured Query Language) 是访问
关系型数据库的标准语言。
• SQL 语言可以分为五种类型:
查询 (QUERY) - SELECT数据处理 (DML)- INSERT, UPDATE, DELETE数据定义 (DDL) - CREATE, ALTER, DROP,
RENAME, TRUNCATE事务控制 (TC) - COMMIT, ROLLBACK,
SAVEPOINT数据控制 (DCL) – GRANT, REVOKE
•SQL 语句可以被嵌入其他语句编写的程序里进行运行,比如 C++ 程序,也可以使用 JDBC 将SQL 语句 写到 Java 程序里。
•SQL 语句也可以使用一些工具运行,与数据库交互,比如 Oracle SQL*Plus , Oracle SQL Developer 以及其他第三方工具。
查询数据
使用 SELECT 查询数据
表 1 表2
查询表中的若干行数据查询表中的若干列
联合不同表中的数据
基本 SELECT 语句
• SELECT 子句指定要查询的数据列。• FROM 子句指定对象表。
SELECT *|{[DISTINCT] column|expression [alias],...}FROM table;
查询所有列SELECT *FROM departments;
查询指定列SELECT department_id, location_idFROM departments;
SELECT 语句编写• 大小写不敏感。• 可以写成一行或多行。• 关键字不能缩写或跨行。• 语句中的子句 (clause) 通常分行输入。• 缩进增加可读性。• 在一般的工具中, SQL 语句一般以分号“ ;” 结
尾。
SELECT 语句中的四则运算
SELECT last_name, salary, 12*(salary+100)FROM employees;
Null 值• Null 值表示相应的值未知、不可用、未被分配。• Null 值不同于数字 0 或空格。• 所有与 Null 值相关的四则运行,结果为 Null 。
定义列别名 (Column Alias)• 重命名列名• 在有四则运算的情况下,可以使列名更具有意义• 列别名在定义时,紧跟列名,以空格或“ as” 分隔• 当列别名的大小写敏感,或者含有空格、特殊字符,需
要使用双引号。
SELECT last_name "Name" , salary*12 "Annual Salary"FROM employees;
…
连接符操作• 将列、字符串连接在一起,作为一个新列。• 连接符为两个竖线:“ ||”• 最终形成的列为字符表达式。
SELECT last_name||job_id AS "Employees"FROM employees;
原义字符串 (Literal Character Strings)
• 原义字符指字符、数字,或者日期。• 日期和字符需要使用单引号封装。• 每行数据显示一次。
…
SELECT last_name ||' is a '||job_id AS "Employee Details"FROM employees;
Quote (q) 操作• 可以选择分隔符。• 可选择任意方便的分隔符,单字节或多字节,或者下列
符号 : [ ], { }, ( ), < > 。• 增加可读性与实用性。SELECT department_name || ' Department' || q'['s Manager Id: ]' || manager_id AS "Department and Manager" FROM departments;
消除重复行SELECT DISTINCT department_idFROM employees;
…
SELECT DISTINCT department_id , job_idFROM employees;
• 可以在多个列之前使用 DISTINCT 修饰词,影响指定的所有列,其结果是这些列组合后的不同值。
DESCRIBE 命令DESCRIBE employees
限制返回结果• 使用 WHERE 子句限制返回结果 :
• WHERE 子句在 FROM 子句之后。
SELECT *|{[DISTINCT] column|expression [alias],...}FROM table[WHERE condition(s)];
SELECT employee_id, last_name, job_id, department_idFROM employeesWHERE department_id = 90 ;
比较运算符 (Comparison Operators)
不等于<>
两个值之间 ( 包括限值 )BETWEEN...AND...
符合列表内的值IN(set)
符合字符样式LIKE
是 null 值IS NULL
小于<
小于或等于<=
大于或等于>=
大于>
等于=
意义运算符
使用比较运算符SELECT last_name, salaryFROM employeesWHERE salary <= 3000 ;
使用比较运算符
SELECT last_name, salaryFROM employeesWHERE salary BETWEEN 2500 AND 3500 ;
• 使用 BETWEEN 操作显示符合范围的值 :
下限 上限
使用比较运算符
SELECT employee_id, last_name, salary, manager_idFROM employeesWHERE manager_id IN (100, 101, 201) ;
• 使用 IN 操作符 显示符合列表内值的数据 :
使用比较运算符• LIKE 操作符筛先符合查找字符串的数据行。• 查找条件可以包括字符或数字:
“ %” 表示数字 0 或者多个字符。“ _” 表示一个字符。
SELECT first_nameFROM employeesWHERE first_name LIKE 'S%' ;
使用比较运算符• 可以同时使用 (%, _) 匹配符 :
• 使用 ESCAPE “ \” 标识符查找值中含有“ %”和 “ _” 字符的数据。
SELECT last_nameFROM employeesWHERE last_name LIKE '_o%' ;
SELECT last_nameFROM employeesWHERE last_name LIKE '%SA\_%' ESCAPE '\';
使用比较运算符
SELECT last_name, manager_idFROM employeesWHERE manager_id IS NULL ;
• 使用 IS NULL 操作检验是否有 Null 值
逻辑运算符
如果条件为假,则返回 TRUE NOT
如果前后两个条件有一个为真,则返回TRUE
OR
如果前后两个条件都为真,则返回 TRUEAND
MeaningOperator
使用逻辑运算符
SELECT employee_id, last_name, job_id, salaryFROM employeesWHERE salary >= 10000AND job_id LIKE '%MAN%' ;
• AND 需要前后两个条件为 TRUE:
使用逻辑运算符• OR 需要前后两个条件有一个为 TRUE:
SELECT employee_id, last_name, job_id, salaryFROM employeesWHERE salary >= 10000OR job_id LIKE '%MAN%' ;
使用逻辑运算符• NOT 操作符可以与 IN, BETWEEN, LIKE, and
NULL 配合使用 :
... WHERE job_id NOT IN ('AC_ACCOUNT', 'AD_VP')
... WHERE salary NOT BETWEEN 10000 AND 15000
... WHERE last_name NOT LIKE '%A%‘
... WHERE commission_pct IS NOT NULL
运算符的优先级规则
可以使用括号改变默认的优先级别
Not equal to6
NOT7
AND 8
OR9
IS [NOT] NULL, LIKE, [NOT] IN4
[NOT] BETWEEN5
比较运算符3
连接运算符2
四则运算1
运算符优先级
排序 ORDER BY• 排序使用 ORDER BY 子句 :
ASC: 升序 ( 默认行为 )
DESC: 倒序• 如果不使用 ORDER BY ,相同的两次查询返回的
结果顺序可以不一样。• 使用 NULL FIRST 和 NULL LAST 指定 NULL
值在排序中的位置。• ORDER BY 子句中的每个列都可以单独指定排序
顺序。
排序 ORDER BY• 默认的排序为升序:
• 数字是最小的值在前 (1 to 999).
• 日期的值最早的在前 (01-JAN-11 在
01-JAN-12 之前 )
• 字符按字母表顺序 (“A” 最前,“ Z” 最后 ).
• Null 值在升序时显示在最后面,在降序时显示在最前面
• 可以使用一个不在 SELECT 列表中的列来排序
替换变量 Substitution Variables• 替换变量临时保存数据,使用“ &” 和“ &&”
符号• 替换变量可用于:
• WHERE 条件子句• ORDER BY 子句• 列表达式• 表名• 整个 SELECT 语句SELECT employee_id, last_name, job_id, &&column_name
FROM employeesORDER BY &column_name ;
SQL 函数 SQL functions
函数
输入
参数 1
参数 2
参数 n
函数进行运算
输出
结果
SQL 函数的两种类型
单行函数 多行函数
每行返回一个结果 多行返回一个结果
函数
单行函数 Single-Row Functions•用于处理数据对象•接收参数,然后输出一个结果•每返回一行数据就要进行运算•每行返回一个结果•可以修改数据类型•可以被嵌套•参数可以是一个列或一个表达式function_name [(arg1, arg2,...)]
转换函数字符函数 数字函数日期函数 一般函数
字符函数 Character Functions
字符函数
LOWERUPPERINITCAP
CONCATSUBSTRLENGTHINSTRLPAD | RPADTRIMREPLACE
大小写转换函数 字符处理函数
大小写转换函数 Case-Conversion
sql courseLOWER('SQL Course')
Sql CourseINITCAP('SQL Course')
SQL COURSEUPPER('SQL Course')
结果函数
字符处理函数
BLACK and BLUE REPLACE('JACK and JUE','J','BL')
10LENGTH('HelloWorld')
6INSTR('HelloWorld', 'W')
*****24000LPAD(salary,10,'*')
24000*****RPAD(salary, 10, '*')
HelloWorldCONCAT('Hello', 'World')
elloWorldTRIM('H' FROM 'HelloWorld')
HelloSUBSTR('HelloWorld',1,5)
结果函数
数字函数
100MOD(1600, 300)
45.93ROUND(45.926, 2)
45.92TRUNC(45.926, 2)
结果函数
日期函数
'08-SEP-95'NEXT_DAY ('01-SEP-95','FRIDAY')
'28-FEB-95'LAST_DAY ('01-FEB-95')
19.6774194MONTHS_BETWEEN ('01-SEP-95','11-JAN-94')
‘29-FEB-96'ADD_MONTHS (‘31-JAN-96',1)
ResultFunction
01-JUL-03TRUNC(SYSDATE ,'MONTH')
01-JAN-03TRUNC(SYSDATE ,'YEAR')
01-AUG-03ROUND(SYSDATE,'MONTH')
01-JAN-04ROUND(SYSDATE ,'YEAR')
转换函数
隐式转换 显式转换
数据类型转换
数据类型的隐式转换
NUMBERVARCHAR2 or CHAR
DATEVARCHAR2 or CHAR
ToFrom
VARCHAR2 or CHARNUMBER
VARCHAR2 or CHARDATE
ToFrom
… where hire_date > '01-JAN-90'
… where name_varchar > 2345
不建议使用隐式转换,可能导致 SQL的性能下降
数据类型的显式转换
数字类型 字符类型
TO_CHAR()
TO_NUMBER()
日期类型
TO_CHAR()
TO_DATE()
日期转换为字符SELECT last_name, TO_CHAR(hire_date, 'fmDD Month YYYY') AS HIREDATEFROM employees;
…
数字转换为字符SELECT TO_CHAR(salary, '$99,999.00') SALARYFROM employeesWHERE last_name = 'Ernst';
字符转换为日期、数字
SQL> select TO_number('6,000.00','99,999.00') from dual;
TO_NUMBER('6,000.00','99,999.00')--------------------------------- 6000
SQL> select TO_date('20110818','YYYYMMDD') from dual;
TO_DATE('201------------18-AUG-11
函数嵌套•单行函数可以嵌套到任意层。•函数的运算顺序是从内到外。
F3(F2(F1(col,arg1),arg2),arg3)
Step 1 = Result 1
Step 2 = Result 2
Step 3 = Result 3
一般函数•下面的函数与 NULL 值的使用有关 :
函数 含义
NVL (expr1, expr2) 如果 expr1 为 null ,则返回 expr2
NVL2 (expr1, expr2, expr3) 如果 expr1 不为 null ,则返回expr2;如果 expr1 为 null ,则返回 expr3
NULLIF (expr1, expr2) 如果 expr1 与 expr2 相同,则返回null ,否则返回 expr1
COALESCE (expr1, expr2, ..., exprn)
按顺序判断 expr1~n ,返回首个不为 null 的表达式的值
条件表达式 Conditional Expressions
•IF-THEN-ELSE 的逻辑判断•有两种方法:
CASEDECODE
CASE expr WHEN comparison_expr1 THEN return_expr1 [WHEN comparison_expr2 THEN return_expr2 WHEN comparison_exprn THEN return_exprn ELSE else_expr]END
DECODE(col|expression, search1, result1 [, search2, result2,...,] [, default])
组函数•对各组的数据行进行运算,每组返回一个值
EMPLOYEES
Maximum salary in EMPLOYEES table
…
组函数类型•对各组的数据行进行运算,每组返回一个值AVGCOUNTMAXMINSTDDEV(平均差 )SUMVARIANCE( 方差 )
组函数
数据分组 GROUP BY 表 EMPLOYEES
…
4400
9500
3500
6400
10033
在 EMPLOYEES 表中,计算每个部门的平均工资
SELECT column, group_function(column)FROM table[WHERE condition][GROUP BY group_by_expression][ORDER BY column];
多个列的 GROUP BY SELECT department_id dept_id, job_id, SUM(salary)FROM employeesGROUP BY department_id, job_id ORDER BY department_id;
组函数的使用• 在 SELECT 子句中没有使用组函数的数据列,必须在
GROUP BY 子句中列出 :
SELECT department_id, COUNT(last_name)FROM employees;
SELECT department_id, job_id, COUNT(last_name)FROM employeesGROUP BY department_id;
组函数的使用• 不能在 WHERE 子句中限制组,需要使用 HAVING 。• 不能在 WHERE 子句中使用组函数。错误:SELECT department_id, AVG(salary)FROM employeesWHERE AVG(salary) > 8000GROUP BY department_id;
正确:SELECT department_id, AVG(salary)FROM employeesGROUP BY department_idHAVING AVG(salary) > 8000;
组函数的嵌套
SELECT MAX(AVG(salary))FROM employeesGROUP BY department_id;
多个表的数据查询
SQL:1999 标准中的 JOIN 语法• 使用 join从多个表中查询数据:
table1.column 表示表 table1 中的列名NATURAL JOIN 用于对两个表中相同的列进行 joinJOIN table2 USING column_name 基于指定的列进行对等 joinJOIN table2 ON table1.column_name = table2.column_name 基于 on 条件指定的列进行对等 joinLEFT/RIGHT/FULL OUTER 用于外连接CROSS JOIN 进行笛卡尔乘积
SELECT table1.column, table2.columnFROM table1[NATURAL JOIN table2] |[JOIN table2 USING (column_name)] |[JOIN table2 ON (table1.column_name = table2.column_name)]|[LEFT|RIGHT|FULL OUTER JOIN table2 ON (table1.column_name = table2.column_name)]|[CROSS JOIN table2];
NATURAL JOIN•NATURAL JOIN 基于两个表中所有相同的列
•返回两个表中相同的列的值相同的数据行
•如果两个表中,名字相同的列的数据类型定义不同,那么会返回错误
使用 USING 进行 join•如果两个表中的列名相同,但数据类型不同,那么可以使用 using 进行对等 join.
•使用 USING只能指定的一个名字相同的列
使用 ON 进行 join•使用 ON 可以指定任意的条件或相关的列进行
join.•使用 ON 可以增加语句的易读性。SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_idFROM employees e JOIN departments dON (e.department_id = d.department_id);
使用 ON 进行 join
SELECT employee_id, city, department_nameFROM employees e JOIN departments dON d.department_id = e.department_id JOIN locations lON d.location_id = l.location_id;
…
额外条件
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_idFROM employees e JOIN departments dON (e.department_id = d.department_id)AND e.manager_id = 149 ;
• 如要使用额外条件,可以使用 AND 或 WHERE子句:
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_idFROM employees e JOIN departments dON (e.department_id = d.department_id)WHERE e.manager_id = 149 ;
或
自连接 self-join•自连接是指一个表与自己进行 join
SELECT worker.last_name emp, manager.last_name mgrFROM employees worker JOIN employees managerON (worker.manager_id = manager.employee_id);
…
表 EMPLOYEES 查询结果
非对等连接 Nonequijoins
SELECT e.last_name, e.salary, j.grade_levelFROM employees e JOIN job_grades jON e.salary BETWEEN j.lowest_sal AND j.highest_sal;
…
外连接 Outer JoinsEMPLOYEESDEPARTMENTS
There are no employees in department 190.
…
内连接和外连接•在 SQL:1999 标准中,只返回匹配记录的
JOIN称为内连接 (inner join)•除返回匹配记录的结果外,还要从左边 (右边 )
的表中返回不相匹配的数据记录的 join称为左外 (右外 ) 连接 (left /right outer join)
•既返回内连接的结果,又返回左外连接与右外连接的 join称为全外连接 (full outer join)
•外连接种类:LEFT OUTERRIGHT OUTERFULL OUTER
左外连接 Left Outer Join
SELECT e.last_name, e.department_id, d.department_nameFROM employees e LEFT OUTER JOIN departments dON (e.department_id = d.department_id) ;
…
全外连接 Left Outer Join
SELECT e.last_name, d.department_id, d.department_nameFROM employees e FULL OUTER JOIN departments dON (e.department_id = d.department_id) ;
…
笛卡尔乘积 Cartesian Products•以下情况会进行笛卡尔乘积 :没有 join 条件Join 条件无效所有数据都符合 join 条件
•尽量避免笛卡尔乘积
子查询 subquery• 问题:谁的工资比员工 A 高 ?
哪个员工的工资比员工 A 高 ?
主查询 :
员工 A 的工资是多少 ?
子查询 :
子查询语法
• 子查询首先运行• 子查询的结果被主查询使用• 子查询放于小括号中• 单行操作符必须与单行子查询匹配• 多行操作符必须与多行子查询匹配
SELECT select_listFROM tableWHERE expr operator
(SELECT select_list FROM table);
Exists • EXISTS 测试子查询是否具有相关的数据行
• 如果找到相关数据行 :子查询停止运行返回结果为 TRUE
• 如果没有找到相关数据行 :返回结果为 FALSE继续子查询,直到子查询结束
NOT Exists 和 NOT in• 如果子查询返回 NULL 值,则 NOT IN 返
回假• 当没有 null 值时 NOT in 与 not exists效
果相同SELECT department_id, department_nameFROM departments dWHERE NOT EXISTS (SELECT 'X' FROM employees WHERE department_id = d.department_id);
查找哪个部门没有员工 ( 表 employees 中有一行数据的 department_id为null)
SELECT department_id, department_nameFROM departments dWHERE department_id NOT IN (SELECT department_id FROM employees);
No rows selected.
IN 、 ANY 、 ALL
• <ANY 意谓着小于子查询返回结果的最大值• >ANY 意谓着大于子查询结果的最小值• =ANY 和 IN 的效果相同• ANY 中的子查询如果返回 0 行,则 <ANY ,
>ANY , =ANY , !=ANY , <=ANY等操作都判断为假,主查询不返回数据
SELECT employee_id, last_name, job_id, salaryFROM employeesWHERE salary < ANY (SELECT salary FROM employees WHERE job_id = 'IT_PROG')AND job_id <> 'IT_PROG';
IN 、 ANY 、 ALL
• <ALL 意谓着小于子查询返回结果的最小值• >ALL 意谓着大于子查询结果的最大值• ALL 中的子查询如果返回 0 行,则 <ALL ,
>ALL , =ALL , !=ALL , <=ALL 等操作都判断为真,主查询返回符合其他条件的数据
SELECT employee_id, last_name, job_id, salaryFROM employeesWHERE salary < ALL (SELECT salary FROM employees WHERE job_id = 'IT_PROG')AND job_id <> 'IT_PROG';
集合操作符 Set Operators
UNION/UNION ALL
A B A B
A B
INTERSECT
A B
MINUS
集合操作符说明•两个查询语句中引用的列数量要一致•第二个查询的列的数据类型须要与第一个查询
的列一一对应•可以使用括号改变执行顺序•除 UNION ALL外,重复行只显示一次•列名的显示以第一个查询为准•默认情况下,除 UNION ALL外,查询结果以
升序排序
UNION
SELECT employee_id, job_idFROM employeesUNIONSELECT employee_id, job_idFROM job_history;
…
…
UNION ALL
SELECT employee_id, job_id, department_idFROM employeesUNION ALLSELECT employee_id, job_id, department_idFROM job_historyORDER BY employee_id;
…
…
INTERSECT
SELECT employee_id, job_idFROM employeesINTERSECTSELECT employee_id, job_idFROM job_history;
MINUS
SELECT employee_idFROM employeesMINUSSELECT employee_idFROM job_history;
…
列数量与类型匹配
SELECT location_id, department_name "Department", TO_CHAR(NULL) "Warehouse location" FROM departmentsUNIONSELECT location_id, TO_CHAR(NULL) "Department", state_provinceFROM locations;
集合操作符与 ORDER BY •ORDER BY 只能在整个查询的最后面出现一
次•ORDER BY 中指定的列,必须在第一个查询
语句中指定的列•默认情况下,第一个查询语句中的第一个列作
为返回结果的排序依据,顺序为升序
多列子查询 Multiple-Column Subqueries
主查询WHERE (MANAGER_ID, DEPARTMENT_ID) IN
子查询结果100 90102 60124 50
多列子查询 Multiple-Column Subqueries
• 不成对比较• 成对比较
成对比较子查询返回与名字为 John 的员工在同一个部门,且同一个领导的员工
SELECT employee_id, manager_id, department_idFROM empl_demoWHERE (manager_id, department_id) IN (SELECT manager_id, department_id FROM empl_demo WHERE first_name = 'John')AND first_name <> 'John';
不成对比较子查询返回与名字为 John 的员工中任意一个领导相符和任意一个部门相符的员工
当名字为 John 多于一人时,与成对比较子查询的返回结果不同。
SELECT employee_id, manager_id, department_idFROM empl_demoWHERE manager_id IN (SELECT manager_id FROM empl_demo WHERE first_name = 'John')AND department_id IN (SELECT department_id FROM empl_demo WHERE first_name = 'John') AND first_name <> 'John';
关联子查询关联子查询用于行与行的处理,关联子查询对每个数据行都要进行 一次。
GET主查询 fetch 到一行数据
EXECUTE子查询根据这行数据的值进行运算
USE根据子查询的结果,决定是否返回这行数据
关联子查询 vs 嵌套子查询嵌套子查询:
子查询首先执行,且执行一次,返回相关结果主查询使用子查询返回的结果进行一次运算
关联子查询:
主查询 fetch 到一行数据根据这行数据,进行子查询运算根据子查询的结果,决定是否返回这行数据重复以上过程,直到主查询结束
使用关联子查询 SELECT column1, column2, ... FROM table1 WHERE column1 operator
(SELECT column1, column2 FROM table2 WHERE expr1 =
.expr2);
outer
outer
SELECT e.employee_id, last_name,e.job_idFROM employees e WHERE 2 <= (SELECT COUNT(*) FROM job_history WHERE employee_id = e.employee_id);
WITH•使用 WITH ,可以在查询中多次引用相同的子
查询•使用 WITH 返回的结果存放在临时空间•在复杂的查询中适当使用 WITH ,可以提高性
能
WITH 示例WITH dept_costs AS ( SELECT d.department_name, SUM(e.salary) AS dept_total FROM employees e JOIN departments d ON e.department_id = d.department_id GROUP BY d.department_name),avg_cost AS ( SELECT SUM(dept_total)/COUNT(*) AS dept_avg FROM dept_costs)SELECT * FROM dept_costs WHERE dept_total > (SELECT dept_avg FROM avg_cost)ORDER BY department_name;
处理数据
DML Data Manipulation Language
•DML 的作用 :添加新的数据到表中修改表中已有的数据删除表中已有的数据
•事务:由一系列的 DML 语句组成,成为一个逻辑工作单元。事务中的语句必须全部成功,否则必须全部回退。
INSERTINSERT INTO departmentsVALUES (100, 'Finance', NULL, NULL);
INSERT INTO departments (department_id, department_name)VALUES (30, 'Purchasing');
INSERT INTO sales_reps(id, name, salary, commission_pct) SELECT employee_id, last_name, salary, commission_pct FROM employees
INSERT INTO employees (employee_id,hire_date)VALUES (113,SYSDATE);
多表 INSERT多表插入有以下种类 :•无条件 INSERT•有条件 INSERT ALL •旋转 (Pivoting) INSERT•条件 INSERT FIRST
Unconditional INSERT ALL
INSERT ALL INTO sal_history VALUES(EMPID,HIREDATE,SAL) INTO mgr_history VALUES(EMPID,MGR,SAL) SELECT employee_id EMPID, hire_date HIREDATE, salary SAL, manager_id MGR FROM employees WHERE employee_id > 200;
Unconditional INSERT ALL
INSERT ALL INTO sal_history VALUES(EMPID,HIREDATE,SAL) INTO mgr_history VALUES(EMPID,MGR,SAL) SELECT employee_id EMPID, hire_date HIREDATE, salary SAL, manager_id MGR FROM employees WHERE employee_id > 200;
Conditional INSERT ALLINSERT ALL
WHEN HIREDATE < '01-JAN-95' THEN
INTO emp_history VALUES(EMPID,HIREDATE,SAL)
WHEN COMM IS NOT NULL THEN
INTO emp_sales VALUES(EMPID,COMM,SAL)
SELECT employee_id EMPID, hire_date HIREDATE,
salary SAL, commission_pct COMM
FROM employees
Conditional INSERT FIRST
INSERT FIRST
WHEN salary < 5000 THEN
INTO sal_low VALUES (employee_id, last_name, salary)
WHEN salary between 5000 and 10000 THEN
INTO sal_mid VALUES (employee_id, last_name, salary)
ELSE
INTO sal_high VALUES (employee_id, last_name, salary)
SELECT employee_id, last_name, salary
FROM employees
Pivoting INSERT•行列转换
600050004000300020006176
FRITHURWEDTUESMONWeek_IDEmp_ID
60006176
50006176
40006176
30006176
20006176
SALESWEEKEmployee_ID
Pivoting INSERT
INSERT ALL INTO sales_info VALUES (employee_id,week_id,sales_MON) INTO sales_info VALUES (employee_id,week_id,sales_TUE) INTO sales_info VALUES (employee_id,week_id,sales_WED) INTO sales_info VALUES (employee_id,week_id,sales_THUR) INTO sales_info VALUES (employee_id,week_id, sales_FRI) SELECT EMPLOYEE_ID, week_id, sales_MON, sales_TUE, sales_WED, sales_THUR,sales_FRI FROM sales_source_data;
UPDATEUPDATE employeesSET department_id = 50WHERE employee_id = 113;
UPDATE copy_empSET department_id = 110;
UPDATE employeesSET department_id = 50WHERE employee_id = null;
UPDATE employeesSET job_id = (SELECT job_id FROM employees WHERE employee_id = 205)WHERE employee_id = 113;
UPDATE 中的关联子查询
UPDATE table1 alias1SET column = (SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
DELETE DELETE FROM departments WHERE department_name = ‘Finance';
DELETE FROM copy_emp;
DELETE FROM employeesWHERE department_id = (SELECT department_id FROM departments WHERE department_name LIKE '%Public%');
DELETE 中的关联子查询
DELETE FROM table1 alias1 WHERE column operator
(SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
TRUNCATETRUNCATE TABLE table_name;
•清空表中的所有数据•删除数据的效率明显比 DELETE高•恢复数据需要备份,代价高
事务事务由以下中的一种组成:•DML 语句•DDL 语句•DCL 语句
事务的开始与结束•开始于第一个被执行的 DML 语句•结束于以下其中一个事件 :
COMMIT 或 ROLLBACK 被运行DDL 或 DCL 被执行 (自动 commit)用户正常退出 (自动 commit)用户非正常退出 (自动 rollback)系统异常中止 (自动 rollback)
事务的显式控制
SAVEPOINT B
SAVEPOINT A
DELETE
INSERT
UPDATE
INSERT
COMMIT时间轴
Transaction
ROLLBACK to SAVEPOINT B
ROLLBACK to SAVEPOINT A
ROLLBACK
Commit 或 Rollback 前的数据状态
•事务中的被修改的数据可以被恢复•事务的发起者可以使用 SELECT 复查数据的修改结果
•事务中的数据修改对其他用户不可见•被修改的数据行被锁定,其他用户不能进行修改
Commit 后的数据状态•数据的修改被保存•以前的数据被覆盖•所有用户可以看到修改的结果•被修改数据上的锁被释放,其他用户可以进行
修改•所有 savepoint 被清除
Rollback 后的数据状态•数据修改被回滚•数据恢复到事务前的状态•锁被释放
语句级回滚 Statement-Level Rollback
•当一个单独的 DML 在执行时失败,那么只有这个语句被回滚
•数据库自动进行隐式的 savepoint•事务中之前的数据修改不被回滚
读一致性 Read Consistency•读一致性确保在任意时间点,数据库都能提供
数据的一致性视图•读一致性要求对于同一份数据 :
查询不需要等待修改修改不需要等待查询修改需要等待修改
读一致性的实现
SELECT *FROM userA.employees;
UPDATE employeesSET salary = 7000WHERE last_name = 'Grant';
Datablocks
Undosegments
Changedand unchanged dataBefore change(“old” data)
用户 A
用户 B
Read-consistentimage
SELECT 中的 FOR UPDATE 子句• 锁定符合条件的数据行
• 锁可以被 COMMIT 或 ROLLBACK释放• 当有一个用户正在修改数据,而另一个用户进行 SELECT
FOR UPDATE去查询这部分数据时,会进行等待,直到第一个用户释放锁。
• 在多表查询时,使用 for update of table1.column_name 时,只有指定列相关的表的一部分符合条件数据被锁定。
SELECT employee_id, salary, commission_pct, job_idFROM employees WHERE job_id = 'SA_REP'FOR UPDATE ORDER BY employee_id;
创建数据库对象
数据库对象
逻辑上代表一个或多个表的数据子集View
产生单调递增的数值Sequence
存放数据行的逻辑存储单元Table
同义词,一个对象的替代名称Synonym
用于改进查询性能Index
描述对象
表的命名规则表名或列名 :•必须以字母开头•长度为 1–30•只能包含 A–Z, a–z, 0–9, _, $, #•同一个用户下的名字不能重复•不能是 ORACLE 系统的保留字
CREATE TABLE•创建表必须满足 :拥有 CREATE TABLE 权限拥有存储空间额度
•需要指定 :表名列名,列的数据类型,列长
CREATE TABLE [schema.]table (column datatype [DEFAULT expr][, ...]);
CREATE TABLE
DESCRIBE dept
CREATE TABLE dept (deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13), create_date DATE DEFAULT SYSDATE);
引用其他用户的表
USERBUSERA
SELECT * FROM userB.employees;
SELECT * FROM userA.employees;
CTAS (Create Table As Select)
CREATE TABLE dept80 AS SELECT employee_id, last_name, salary*12 ANNSAL, hire_date FROM employees WHERE department_id = 80;
DESCRIBE dept80
数据类型
未经处理的类型RAW and LONG RAW
二进制数据类型 (up to 4 GB)BLOB
存储在外部文件的二进制数据类型 (up to 4 GB)BFILE
日期类型DATE
变长的字符类型 (up to 2 GB)LONG
字符类型 (up to 4 GB)CLOB
代表表中数据行的唯一地址ROWID
定长的字符数据CHAR(size)
变长的数值类型NUMBER(p,s)
变长的字符类型VARCHAR2(size)
描述Data Type
数据类型
存储时间间隔的类型INTERVAL YEAR TO MONTH
存储时间间隔的类型INTERVAL DAY TO SECOND
较精细的日期类型TIMESTAMP
描述Data Type
约束 Constraints•约束增强表级规则•如果有依赖关系,约束阻止数据删除•下列约束类型是有效的 :
NOT NULLUNIQUEPRIMARY KEYFOREIGN KEY 引用其他表的列值CHECK
约束 Constraints•用户可以指定约束的名称,或者由数据库自动生成格式为 SYS_Cn 的名字
•可以在以下情况创建约束 :在表的创建时在表的创建后
•可以在列级或表级定义约束•可以通过数据字典查询约束的详细定义 .
约束 Constraints•语法
•列级约束
•表级约束
CREATE TABLE [schema.]table (column datatype [DEFAULT expr] [column_constraint], ... [table_constraint][,...]);
column,... [CONSTRAINT constraint_name] constraint_type (column, ...),
column [CONSTRAINT constraint_name] constraint_type,
约束 Constraints•列级约束
•表级约束
CREATE TABLE employees( employee_id NUMBER(6) CONSTRAINT emp_emp_id_pk PRIMARY KEY, first_name VARCHAR2(20), ...);
CREATE TABLE employees( employee_id NUMBER(6), first_name VARCHAR2(20), ... job_id VARCHAR2(10) NOT NULL, CONSTRAINT emp_emp_id_pk PRIMARY KEY (EMPLOYEE_ID));
1
2
外键约束 FOREIGN KEY Constraint部门表
员工表外键
INSERT INTO 操作 允许 (部门表的主键列不存在数值9)允许
主键
…
…
外键约束 FOREIGN KEY Constraint
• FOREIGN KEY (referential integrity)约束将一个列或几个列的组合作为一个外键,这个外键与同一个表或另一个表的主键或唯一键建立参考关系
• 外键所在表称为子表 (child table) ,被参考的主键或唯一键所在的表称为父表 (parent table)
• 一个外键的值必须与父表中存在的值匹配,或者为 NULLCREATE TABLE employees( employee_id NUMBER(6), last_name VARCHAR2(25) NOT NULL, email VARCHAR2(25), salary NUMBER(8,2), commission_pct NUMBER(2,2), hire_date DATE NOT NULL,... department_id NUMBER(4), CONSTRAINT emp_dept_fk FOREIGN KEY (department_id) REFERENCES departments(department_id), CONSTRAINT emp_email_uk UNIQUE(email));
外键约束 FOREIGN KEY Constraint
• FOREIGN KEY :定义外键
• REFERENCES: 定义父表中的主键或唯一键
• ON DELETE CASCADE: 当父表中的一行数据被删除的同时,也删除子表中 的相关数据行。
• ON DELETE SET NULL: 当父表中的一行数据被删除的同时,将子表中 的相关数据置为 NULL 。
CHECK约束 CHECK Constraint• 定义一个每行数据必须满足的条件,但以下表达式不能使用:
CURRVAL, NEXTVAL, LEVEL和 ROWNUM伪列SYSDATE, UID, USER 和 USERENV 函数与其他行的其他数值相关的查询
• 一个列上可以定义多个 CHECK约束
..., salary NUMBER(2) CONSTRAINT emp_salary_min CHECK (salary > 0),...
Alter Table 语句ALTER TABLE 的作用 :• 增加一个列• 修改一个列的定义• 定义一个新列的默认值• 删除一个列• 重命名一个列的名称• 将表置为 read-only , read-write状态
ALTER TABLE employees READ ONLY;
ALTER TABLE employees READ WRITE;
Drop Table 语句DROP TABLE 的作用 :• 将表移动到回收站 (recyclebin)• 使有依赖关系的数据库对象失效 • 移除相关权限
DROP TABLE dept80;
创建其他对象
逻辑上显示一个或多个表的数据子集,不占用存储空间
View
产生单调递增的数值Sequence
由数据行组成,基本的存储单元Table
同义词,一个对象的替代名称Synonym
增强查询性能Index
描述对象
视图 VIEW
Yes
No
No
One
Simple Views
Yes包含函数
Yes使用 group by
One or more相关表的个数
Not always通过视图进行 DML 操作
Complex Views特点
简单视图与复杂视图:
创建视图
CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view [(alias[, alias]...)] AS subquery[WITH CHECK OPTION [CONSTRAINT constraint]][WITH READ ONLY [CONSTRAINT constraint]];
CREATE OR REPLACE VIEW empvu80 (id_number, name, sal, department_id)AS SELECT employee_id, first_name || ' ' || last_name, salary, department_id FROM employees WHERE department_id = 80;
对视图进行 DML 操作的规则• 对简单视图总是可以进行 DML 操作
• 如果视图含有以下内容时,不能删除数据行 : 组函数 Group functions 有 GROUP BY 子句 有 DISTINCT 有伪列 ROWNUM
对视图进行 DML 操作的规则• 如果视图含有以下内容时,不能修改数据行 :
组函数 Group functions 有 GROUP BY 子句 有 DISTINCT 有伪列 ROWNUM 以表达式定义的列 (for example, SALARY * 12)
对视图进行 DML 操作的规则• 如果视图含有以下内容时,不能插入数据行 :
组函数 Group functions 有 GROUP BY 子句 有 DISTINCT 有伪列 ROWNUM 以表达式定义的列 (for example, SALARY * 12) 基表中的 NOT NULL 列在视图中不可见时
使用 WITH CHECK OPTION• WITH CHECK OPTION 可以限制 DML 操作 :
CREATE OR REPLACE VIEW empvu20AS SELECT * FROM employees WHERE department_id = 20 WITH CHECK OPTION CONSTRAINT empvu20_ck ;
使用 WITH READ ONLY• WITH READ ONLY 选项防止DML 操作
CREATE OR REPLACE VIEW empvu10 (employee_number, employee_name, job_title)AS SELECT employee_id, last_name, job_id FROM employees WHERE department_id = 10 WITH READ ONLY ;
删除视图•删除视图对基表没有影响,不会丢失数据
DROP VIEW view;
DROP VIEW empvu80;
序列 Sequences序列可以:• 可以自动生成具有唯一性的数值• 是可共享对象• 可以用于创建主键值• 可以替代相同功能的自定义程序• 当设置 CACHE 时,可以增加效率
1
2 4
3 5
6 8
7
10
9
创建序列CREATE SEQUENCE sequence [INCREMENT BY n] [START WITH n] [{MAXVALUE n | NOMAXVALUE}] [{MINVALUE n | NOMINVALUE}] [{CYCLE | NOCYCLE}] [{CACHE n | NOCACHE}];
NEXTVAL 和 CURRVAL• NEXTVAL 返回下一个可用的序列值。• CURRVAL 返回当前用户的当前的序列值• 在使用 CURRVAL 前,必须先使用 NEXTVAL生成
一个序列值
使用序列•插入一个新的部门“ Support” , location_ID 为
2500:
• 查看序列 DEPT_DEPTID_SEQ 的当前值
INSERT INTO departments(department_id, department_name, location_id)VALUES (dept_deptid_seq.NEXTVAL, 'Support', 2500);
SELECT dept_deptid_seq.CURRVALFROM dual;
缓存序列值•缓存序列值增加性能• 序列值间断 (gap) 在以下情况出现:发生 rollback系统异常关闭序列值被用于另一个表
修改序列ALTER SEQUENCE dept_deptid_seq INCREMENT BY 20 MAXVALUE 999999 NOCACHE NOCYCLE;
•只有以后的序列值受影响• 如果要更改起始值,只能重新创建序列•会进行一些验证• 要删除序列,使用 DROP 语句 :DROP SEQUENCE dept_deptid_seq;
索引 Indexes索引:• 是一个用户对象• 增加性能•快速定位数据,降低磁盘 IO•索引可以被更改或删除,而不影响表和其他索引的数据•创建完成后,数据库自动使用与维护索引
索引是怎样被创建的?•自动 : 当定义了一个主键或唯一性键时,唯一性索引可
以被自动创建。
•手动 : 除了唯一性索引,用户还可以创建非唯一性索引
创建索引• 在一个或多个列上创建索引 :
• 以下索引可以根据 last_name 列的条件,加快查询:CREATE INDEX emp_last_name_idxON employees(last_name);
CREATE [UNIQUE][BITMAP]INDEX indexON table (column[, column]...);
索引创建建议
以下情况时,不要创建索引 :
查询条件中不常出现的列
表很小,或者大多数查询涉及的数据大于 4%
更新频繁的表
一个列的值拥有大量的 NULL 值一个或多个列经常在 WHERE 子句或 join 条件中被引用
一个列的值较宽泛,范围大
需要引用的列包含在表达式中
表非常大,绝大多数的查询涉及的数据小于 4%
以下情况时,创建索引 :
删除索引• DROP INDEX :
•删除 emp_last_name_idx :
•删除索引,需要是索引的所有者,或者有 DROP ANY INDEX 系统权限 .
DROP INDEX emp_last_name_idx;
DROP INDEX index;
同义词 Synonym 同义词可以 :• 引用其他用户下的表时更方便• 相对于原表,缩短引用表名所需长度
CREATE [PUBLIC] SYNONYM synonymFOR object;
创建和删除同义词•创建更短的名字 :
•删除同义词 :
• 不影响原对象
CREATE SYNONYM d_sumFOR dept_sum_vu;
DROP SYNONYM d_sum;
控制用户访问
控制用户访问
DB管理员
用户
用户名、密码权限
权限 Privileges• 系统权限 : 用于在数据库内进行特定的操作
• 对象权限 : 处理数据库对象的内容
• Schemas: 对象的集合,如 tables, views, and sequences
系统权限•超过 100 个系统权限• 数据库管理员拥有高级的系统权限,如:创建新用户删除用户删除表备份表
创建用户
CREATE USER demoIDENTIFIED BY demo;
CREATE USER user IDENTIFIED BY password;
用户系统权限• 在用户被创建后,管理员可以将权限赋于用户 .
• 比如一个程序开发用户,可以有以下权限 :CREATE SESSIONCREATE TABLECREATE SEQUENCECREATE VIEWCREATE PROCEDURE
GRANT privilege [, privilege...]TO user [, user| role, PUBLIC...];
GRANT create session, create table, create sequence, create viewTO demo;
角色 Roles
不使用 roles 进行权限分配 使用 roles 进行权限分配
权限
用户
Manager
创建角色
CREATE ROLE manager;
GRANT create table, create view TO manager;
GRANT manager TO BELL, KOCHHAR;
对象权限对象 权限 表 视图 序列
ALTER
DELETE
INDEX
INSERT
REFERENCES
SELECT
UPDATE
对象权限• 不同类型的对象有其自身的对象权限• 对象的所有者拥有这个对象的全部权限• 所有者可以将对象权限赋予其他用户
GRANT object_priv [(columns)] ON object TO {user|role|PUBLIC} [WITH GRANT OPTION];
赋予对象权限• 将查询 EMPLOYEES 的权限赋予 demo 用户 :
• 将特定列的 UPDATE权限赋予用户和角色:
GRANT selectON employeesTO demo;
GRANT update (department_name, location_id)ON departmentsTO demo, manager;
回收对象权限• 使用 REVOKE 收回权限• 通过WITH GRANT OPTION赋给其他用户的权限也
同时收回 .
REVOKE {privilege [, privilege...]|ALL}ON objectFROM {user[, user...]|role|PUBLIC}[CASCADE CONSTRAINTS];