DDL语句
DDL(Data Definition Language,数据定义语言)是SQL语言的一个子集,用于定义和管理数据库对象的结构。在Oracle数据库中,DDL语句主要包括创建、修改和删除数据库对象的命令。
1. CREATE语句
用于创建数据库对象:
-- 创建表
CREATE TABLE employees (
employee_id NUMBER(6) PRIMARY KEY,
first_name VARCHAR2(20),
last_name VARCHAR2(25) NOT NULL,
email VARCHAR2(25) UNIQUE,
hire_date DATE DEFAULT SYSDATE,
salary NUMBER(8,2),
department_id NUMBER(4)
);
-- 创建索引
CREATE INDEX emp_last_name_idx ON employees(last_name);
-- 创建视图
CREATE VIEW emp_dept_view AS
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id;
-- 创建序列
CREATE SEQUENCE emp_seq
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- 创建同义词
CREATE SYNONYM emp FOR employees;2. ALTER语句
用于修改数据库对象的结构:
-- 添加列
ALTER TABLE employees ADD (middle_name VARCHAR2(20));
-- 修改列
ALTER TABLE employees MODIFY (email VARCHAR2(30));
-- 删除列
ALTER TABLE employees DROP COLUMN middle_name;
-- 重命名列
ALTER TABLE employees RENAME COLUMN email TO email_address;
-- 添加约束
ALTER TABLE employees ADD CONSTRAINT emp_salary_min
CHECK (salary > 0);
-- 禁用约束
ALTER TABLE employees DISABLE CONSTRAINT emp_salary_min;
-- 重命名表
ALTER TABLE employees RENAME TO staff;3. DROP语句
用于删除数据库对象:
-- 删除表
DROP TABLE employees;
-- 删除表(带约束)
DROP TABLE employees CASCADE CONSTRAINTS;
-- 删除视图
DROP VIEW emp_dept_view;
-- 删除索引
DROP INDEX emp_last_name_idx;
-- 删除序列
DROP SEQUENCE emp_seq;4. TRUNCATE语句
用于快速删除表中的所有数据,但保留表结构:
TRUNCATE TABLE employees;5. RENAME语句
用于重命名数据库对象:
RENAME employees TO staff;DML语句
DML(Data Manipulation Language,数据操纵语言)是SQL中用于操作数据库中数据的语言子集,主要包括数据的插入、更新、删除和查询操作。
1. INSERT语句(数据插入)
基本插入:
INSERT INTO employees (employee_id, last_name, email, hire_date, job_id)
VALUES (1001, 'Smith', 'jsmith@example.com', SYSDATE, 'IT_PROG');多行插入:
INSERT ALL
INTO employees VALUES (1002, 'John', 'Doe', 'jdoe@example.com', SYSDATE, 'SA_REP', 6000, NULL, 145, 80)
INTO employees VALUES (1003, 'Jane', 'Smith', 'jsmith@example.com', SYSDATE, 'IT_PROG', 7000, NULL, 103, 60)
SELECT 1 FROM dual;从查询结果插入:
INSERT INTO employee_archive
SELECT * FROM employees
WHERE hire_date < TO_DATE('01-JAN-2000', 'DD-MON-YYYY');2. UPDATE语句(数据更新)
基本更新:
UPDATE employees
SET salary = salary * 1.1
WHERE department_id = 20;多列更新:
UPDATE employees
SET salary = salary * 1.05,
commission_pct = 0.1
WHERE job_id = 'SA_REP';使用子查询更新:
UPDATE employees e
SET salary = (SELECT AVG(salary) FROM employees)
WHERE e.salary < (SELECT AVG(salary) FROM employees);3. DELETE语句(数据删除)
基本删除:
DELETE FROM employees
WHERE employee_id = 1001;使用子查询删除:
DELETE FROM employees
WHERE department_id IN
(SELECT department_id FROM departments WHERE location_id = 1700);全表数据删除:
DELETE FROM employee_backup;4. MERGE语句(合并操作,Oracle特有)
MERGE INTO employees_target t
USING employees_source s
ON (t.employee_id = s.employee_id)
WHEN MATCHED THEN
UPDATE SET t.salary = s.salary, t.department_id = s.department_id
WHEN NOT MATCHED THEN
INSERT (employee_id, last_name, salary, department_id)
VALUES (s.employee_id, s.last_name, s.salary, s.department_id);Oracle DML特性
*事务控制:
COMMIT:提交事务
ROLLBACK:回滚事务
SAVEPOINT:设置保存点
*锁定机制:
SELECT ... FOR UPDATE:锁定查询结果行
*闪回查询:
SELECT * FROM employees
AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '30' MINUTE;*批量绑定:
FORALL i IN 1..emp_ids.COUNT
UPDATE employees SET salary = salaries(i)
WHERE employee_id = emp_ids(i);高级DML操作
1. 层次查询
SELECT employee_id, last_name, manager_id, LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;2. 分析函数
SELECT department_id, last_name, salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) as rank
FROM employees;3. 物化视图
CREATE MATERIALIZED VIEW emp_summary_mvDQL语句
SELECT在数据库中是使用较为频繁的访问语句,虽然它只有一条命令,但是由于其丰富多样的灵动性,以及它附有子查询的强大功能,还可以组成各式各样的复杂查询语句,能够查询并统计出各种错综复杂的数据。
SELECT语句可以根据不同用户的需求查询数据库中的数据,并且SELECT可以实行简单的计算和统计。在数据库中执行最简化的SELECT语句只有一个FROM子句,代码格式如下:
SELECT 表达式 FROM 表名;
;是在设计完每个SQL语言后都必须添加的符号,对于新手学习非常重要
在SELECT语句查询时,可以增添一个或多个列名或者带入多个不同型式的表达式,用来指定需要查询出的列,或者对某样数据的计算。在FROM子句中也可以指定一个或多个表名,用来指定此次要查询所涉及到的表。查询的结果也是可以返回一行或多行数据,每行由一个或多个列的列值组成。
完整的SELECT语句包括WHERE、ORDER、GROUP等子句。具体格式如下:
SELECT 表达式
FROM 表名
WHERE 条件
GROUP BY 列名
HAVING 条件
ORDER BY 表达式;
SELECT语句中最灵活且使用次数最多的就是WHERE子句中的查询条件,这个条件用来指定查询什么样的数据。接下来分别介绍SELECT多元化组成部分
1、查询语句的基本用法
如果需要查询某个表中一个或多个列的数据,需要在SELECT命令后指定列的名称,并且在FROM子句后面添加所涉及的表名。格式如下:
SELECT 列1,列2....
FROM 表名;
SQL查询出来的结果,是从表中将指定列的数据显示出来。如果要查询DEPT表中的DEPTNO和SAL列,对应的SELECT查询语句如下:
SELECT DEPTNO,SAL FROM EMP;
查询这样的SQL语句可以在ORACLE自带的工具SQL*PLUS执行,也可以在其他SQL软件或应用程序中执行。在本文中详细介绍的是SQL语言是在SQL*PLUS中执行,因此所以;符号是必不可少的基本用法。在类似Linux或windows操作系统中的终端窗口,输入其命令sqlplus,并且指定其用户名和密码,即可登录数据库服务器。例如Linux服务器中shell提示符:
$SQLPLUS SCOTT/TIGER
在SQL语句中除了字符串外,各个部分是大小写不敏感的。SQL语句可以在一行中书写,也可以分行书写。命令的执行结果为:
DEPTNO LOC
10 NEW YORK
20 DALLAS
30 CHICAGO
40 BOSTON
如果要查询出表中所有列的数据,可以使用*符号代替其所有的列名。命令如下:
select * from emp;
如果不清楚表的结构,可以在SQL*PLUS中执行命令DESCRIBE可以简写为DESC,查看具体表的结构。这个命令的参数是表名,或者其他对象名。注意,这条命令不是SQL命令,而是SQL*PLUS中的命令。执行命令如下:
SELECT语句中可以给列定义别名,在执行语句显示结果时,列的标题就是定义的别名名称,在整个SQL语句里都可以使用该别名,使用别名的格式为:
SELECT 列1 AS 别名1,列2 AS 别名2 ……
也可以直接忽略掉AS关键字,直接定义其别名。例如:
SELECT empno AS 员工编号,sal 工资 FROM emp;
在查询结果中如果显示有多行重复值,可以考虑使用DISTINCT关键字去掉多余的重复值。重复行是指在SELECT语句中涉及的所有列的列值完全相同的行,例如,要查询员工所分布的部门编号,可以用DISTINCT关键字去掉其中的重复行:
SELECT DISTINCT deptno AS部门编号 FROM emp;
命令执行的结果为:
部门编号
-------
10
20
30
在SELECT语句中还可以对查询的列进行简单的计算,也可以在两个列之间进行计算,或者将某个列与其他表达式,或者两个表达式进行计算。表中列出了在SELECT语句可以使用的运算符。
例如,查询出emp表中员工的工资和奖金之和,查询的语句为:
SELECT sal+comm AS总收入 FROM emp;
这条语句的执行结果为:
总收入
----------
2100
1950
....
在emp表中共有12名员工,每名员工都有工资。如果奖金为空,对应的计算结果就为空。空值与0或者空格是不同的。空值就是没有数据,而0或者空格是实实在在的数据,就像考试没有成绩和得了0分是不一样的。为了解决空值的计算问题,SQL提供了一个函数,这个函数是NVL,它的功能是把空值转换为其他可以参加运算的数据。这个函数的调用格式是:NVL(表达式,替代值)
当表达式的结果为空时,这个函数就把表达式的值用指定的值代替。有了这个函数,我们就可以在奖金为空时把它用0或者其他数据代替。改进后的查询工资和奖金之和的语句为:SELECT sal+nvl(comm,0)AS总收入FROM emp; 总收入 ---------- 600 2900 1650 1975 ……
在Oracle数据库中提供了一个特殊的表为dual,这个表的结构为:DESC dual,通过查询这个表,发现表中只有一行数据,可见,dual表只有一个列,而且中有一行数据。所以,在进行与具体的表无关的运算时,可以在FROM子句中指定dual表,这样可以保证计算的结果只显示一次。例如:
SELECT*FROM dual;
DUMMY
-----
X2、查询语句中的条件
在SELECT语句中由于没有限制特定的条件规则,所以查询出的结果返回的都是所有行显示,如果只是想查询出某一部分行的数据,可以通过WHERE子句来指定条件,WHERE子句中指定的条件是一个关系表达式,如果表达式结果则为真,条件成立,否则条件不成立。例如:查询出emp表中部门编号为10的员工名称和工资。
SELECT ename, sal FROM emp WHERE deptno=10;
=运算符只能对字符串进行精确比对,通常需要模糊匹配查询我们可以用LIKE运算符表达。在LIKE关系表达式中可以使用两个通配符:%和_,其中%可以代替多个字符,注意%也包括空字符,_只能代替一个字符。例如:要查询出员工姓名内包含ME的字符串,语句为:
SELECT ename FROM emp WHERE ename LIKE'%ME%';
又例如要查询员工姓名内,第一个字符是任意字符,第二个字符是B,然后是若干任意字符,语句为:
SELECT ename FROM emp WHERE ename LIKE'_B%';
IN运算符用来表达一个集合的元素进行比较,表达式与集合中的元素一一比较,要与其中一个相等,则条件成立。如果没有任何一个元素与表达式的值相等,则条件不成立。例如:查询emp表中姓名包含如下名称的员工:
SELECT ename FROM emp WHERE ename IN ('HALO','FED','HEL');
BETWEEN运算符用于将表达式的值与两个指定数据进行比较,如果表达式的值在这两个数据之间,则条件成立。例如:查询emp表中工资500到2000之间的员工:
SELECT ename,sal FROM emp WHERE sal BETWEEN 500 AND 2000;
如果使用“>”或“<”等运算符,来编写上述例子条件,语句为:
SELECT ename,sal FROM emp WHERE sal >=500 AND sal <=2000;
需要体现出多个反应的条件,在复杂的查询语句条件中可以通过AND或OR运算符表达,当多个表达式连接起来后,就可以构成一个逻辑表达式,表达式里的结果要么为true要么为false。
NOT运算符表达方式是对值取反,它的用法是在关系表达式上加上它。例如:要查询工资不大于2000的员工姓名,语句为:
SELECT ename FROM emp WHERE NOT sal<2000;
语句等价于为:
SELECT ename FROM emp WHERE sal>=2000;
对两个条件同时取反以后的SELECT语句为:
SELECT ename FROM emp WHERE NOT (sal>500 AND sal<2000);
WHERE语句中要注意空值的运算。值与任何数据进行赋值运算、四则运算以及关系运算时,结果都为空值。例如,要查询姓名不为空的所有员工的工资,查询的结果应该是所有员工的工资,但是结果却为空。
SELECT sal FROM emp WHERE ename!= NULL;
判断某个表达式是否为空值的运算符是“IS NULL”,判断是否不为空值的运算符是“IS NOT NULL”。例如,用运算符“IS NOT NULL”重新构造上述SELECT语句,将得到我们希望的结果。语句为:
SELECT sal FROM emp WHERE ename IS NOT NULL;3、查询语句中的单行函数
3.1、字符串处理函数:
1、LENGTH - 返回字符串长度
SELECT LENGTH('Oracle') FROM dual; -- 返回 62、LOWER/UPPER/INITCAP - 大小写转换
SELECT LOWER('ORACLE'), UPPER('oracle'), INITCAP('oracle database')
FROM dual;
-- 返回: oracle, ORACLE, Oracle Database3、SUBSTR - 截取子字符串
SELECT SUBSTR('Oracle Database', 8, 8) FROM dual; -- 返回 'Database'4、INSTR - 查找子字符串位置
SELECT INSTR('Oracle Database', 'Data') FROM dual; -- 返回 85、CONCAT - 连接字符串(或使用 || 运算符)
SELECT CONCAT('Oracle', ' Database') FROM dual; -- 返回 'Oracle Database'
SELECT 'Oracle' || ' Database' FROM dual; -- 同上6、REPLACE - 替换字符串
SELECT REPLACE('Oracle Database', 'Database', 'DB') FROM dual; -- 返回 'Oracle DB'7、TRANSLATE - 字符级替换
SELECT TRANSLATE('12345', '123', 'ABC') FROM dual; -- 返回 'ABC45'8、LPAD/RPAD - 字符串填充
SELECT LPAD('Oracle', 10, '*'), RPAD('Oracle', 10, '*') FROM dual;
-- 返回: '****Oracle', 'Oracle****'9、TRIM/LTRIM/RTRIM - 去除空格或指定字符
SELECT TRIM(' Oracle '), LTRIM('xxOracle', 'x'), RTRIM('Oraclexx', 'x')
FROM dual;
-- 返回: 'Oracle', 'Oracle', 'Oracle'10、ASCII/CHR - ASCII码转换
SELECT ASCII('A'), CHR(65) FROM dual; -- 返回: 65, 'A'11、REGEXP_SUBSTR/REGEXP_REPLACE/REGEXP_INSTR/REGEXP_LIKE - 正则表达式函数
SELECT REGEXP_SUBSTR('100 Oracle Parkway', '[0-9]+') FROM dual; -- 返回 '100'
SELECT REGEXP_REPLACE('500 Oracle Parkway', '[0-9]+', '***') FROM dual; -- 返回 '*** Oracle Parkway'12、NLS_INITCAP/NLS_LOWER/NLS_UPPER - 支持NLS的字符串转换
SELECT NLS_INITCAP('straße', 'NLS_SORT=XGERMAN') FROM dual; -- 返回 'Straße'13、TO_CHAR - 数字/日期转为字符串
SELECT TO_CHAR(1234.56, '$9,999.99') FROM dual; -- 返回 '$1,234.56'14、DECODE/CASE - 条件字符串处理
SELECT DECODE('A', 'A', 'Alpha', 'B', 'Beta', 'Other') FROM dual; -- 返回 'Alpha'15、LISTAGG (11gR2+) - 字符串聚合
SELECT LISTAGG(ename, ', ') WITHIN GROUP (ORDER BY ename)
FROM emp;3.2、数学函数:
1、ABS - 绝对值
SELECT ABS(-15) FROM dual; -- 返回 152、SIGN - 符号函数
SELECT SIGN(-23), SIGN(0), SIGN(45) FROM dual; -- 返回 -1, 0, 13、MOD - 取模运算
SELECT MOD(11, 4) FROM dual; -- 返回 3 (11除以4的余数)4、POWER - 幂运算
SELECT POWER(3, 2) FROM dual; -- 返回 9 (3的2次方)5、SQRT - 平方根
SELECT SQRT(25) FROM dual; -- 返回 56、ROUND - 四舍五入
SELECT ROUND(15.79), ROUND(15.79, 1), ROUND(15.79, -1) FROM dual;
-- 返回: 16, 15.8, 207、TRUNC - 截断数字
SELECT TRUNC(15.79), TRUNC(15.79, 1), TRUNC(15.79, -1) FROM dual;
-- 返回: 15, 15.7, 108、CEIL/FLOOR - 向上/向下取整
SELECT CEIL(15.2), FLOOR(15.9) FROM dual; -- 返回: 16, 159、SIN/COS/TAN - 正弦/余弦/正切
SELECT SIN(30 * 3.14159265359/180) FROM dual; -- 30度的正弦值10、ASIN/ACOS/ATAN - 反正弦/反余弦/反正切
SELECT ASIN(0.5) * 180/3.14159265359 FROM dual; -- 返回30(度)11、ATAN2 - 两个参数的反正切
SELECT ATAN2(1, 1) * 180/3.14159265359 FROM dual; -- 返回45(度)12、EXP - e的幂
SELECT EXP(1) FROM dual; -- 返回e的值≈2.7182813、LN/LOG - 自然对数/指定底数的对数
SELECT LN(10), LOG(10, 100) FROM dual; -- 返回≈2.302585, 214、GREATEST/LEAST - 最大/最小值
SELECT GREATEST(10, 20, 5), LEAST(10, 20, 5) FROM dual; -- 返回20, 515、WIDTH_BUCKET - 等宽分桶
SELECT WIDTH_BUCKET(75, 0, 100, 4) FROM dual; -- 返回3(将0-100分为4个桶)16、BITAND - 位与运算
SELECT BITAND(6, 3) FROM dual; -- 返回2 (0110 AND 0011 = 0010)17、DBMS_RANDOM - 随机数生成(需要包)
SELECT DBMS_RANDOM.VALUE FROM dual; -- 返回0-1之间的随机数
SELECT DBMS_RANDOM.VALUE(10, 20) FROM dual; -- 返回10-20之间的随机数18、TO_NUMBER - 字符串转数字
SELECT TO_NUMBER('$1,234.56', '$9,999.99') FROM dual; -- 返回1234.5619、NANVL - 处理NaN值(非数字)
SELECT NANVL(0/0, 0) FROM dual; -- 当第一个参数是NaN时返回0REMAINDER - 计算余数(与MOD类似但使用ROUND而非FLOOR)
SELECT REMAINDER(11, 4) FROM dual; -- 返回-1 (不同于MOD(11,4)=3)3.3、日期函数:
1、SYSDATE - 当前系统日期和时间
SELECT SYSDATE FROM dual; -- 返回当前数据库服务器日期和时间2、SYSTIMESTAMP - 当前系统时间戳(带时区)
SELECT SYSTIMESTAMP FROM dual; -- 返回更精确的时间戳,包含小数秒和时区3、CURRENT_DATE - 当前会话日期(考虑会话时区)
SELECT CURRENT_DATE FROM dual; -- 返回会话时区的当前日期4、CURRENT_TIMESTAMP - 当前会话时间戳(带时区)
SELECT CURRENT_TIMESTAMP FROM dual; -- 返回会话时区的时间戳5、ADD_MONTHS - 添加月份
SELECT ADD_MONTHS(SYSDATE, 3) FROM dual; -- 当前日期加3个月6、MONTHS_BETWEEN - 计算月份差
SELECT MONTHS_BETWEEN('15-JUL-2023', '15-MAR-2023') FROM dual; -- 返回47、NEXT_DAY - 下一个指定星期几的日期
SELECT NEXT_DAY(SYSDATE, 'FRIDAY') FROM dual; -- 返回下一个周五的日期8、LAST_DAY - 月份的最后一天
SELECT LAST_DAY(SYSDATE) FROM dual; -- 返回当前月份的最后一天9、EXTRACT - 提取日期部分
SELECT EXTRACT(YEAR FROM SYSDATE) FROM dual; -- 返回当前年份
SELECT EXTRACT(MONTH FROM SYSDATE) FROM dual; -- 返回当前月份
SELECT EXTRACT(DAY FROM SYSDATE) FROM dual; -- 返回当前日10、TO_CHAR (日期格式化) - 日期转字符串
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM dual;
-- 返回格式如: 2023-07-15 14:30:4511、TO_DATE - 字符串转日期
SELECT TO_DATE('2023-07-15', 'YYYY-MM-DD') FROM dual;
-- 将字符串转换为日期类型12、ROUND (日期) - 日期舍入
SELECT ROUND(SYSDATE, 'MONTH') FROM dual; -- 舍入到最近月份的第一天
SELECT ROUND(SYSDATE, 'YEAR') FROM dual; -- 舍入到最近年份的第一天13、TRUNC (日期) - 日期截断
SELECT TRUNC(SYSDATE, 'MONTH') FROM dual; -- 截断到当月第一天
SELECT TRUNC(SYSDATE, 'YEAR') FROM dual; -- 截断到当年第一天3.4、类型转换函数:
1、TO_NUMBER - 将字符串转换为数字
SELECT TO_NUMBER('1234.56') FROM dual;
SELECT TO_NUMBER('$1,234.56', '$9,999.99') FROM dual; -- 使用格式模型2、TO_CHAR (数字转换) - 将数字转换为字符串
SELECT TO_CHAR(1234.56, '$9,999.99') FROM dual; -- 返回 '$1,234.56'
SELECT TO_CHAR(1234.56, 'L9,999.99') FROM dual; -- 返回本地货币格式3、TO_CHAR (日期转换) - 将日期转换为字符串
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM dual;
SELECT TO_CHAR(SYSDATE, 'Day, Month DD, YYYY') FROM dual;4、TO_DATE - 将字符串转换为日期
SELECT TO_DATE('2023-07-15', 'YYYY-MM-DD') FROM dual;
SELECT TO_DATE('15-July-2023', 'DD-Month-YYYY') FROM dual;5、TO_TIMESTAMP - 将字符串转换为时间戳
SELECT TO_TIMESTAMP('2023-07-15 14:30:45.123', 'YYYY-MM-DD HH24:MI:SS.FF') FROM dual;6、TO_TIMESTAMP_TZ - 将字符串转换为带时区的时间戳
SELECT TO_TIMESTAMP_TZ('2023-07-15 14:30:45.123 +08:00', 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM') FROM dual;4、分组函数与分组统计
4.1、常用聚合函数
COUNT - 计数
SELECT COUNT(*) FROM employees; -- 计算所有行数
SELECT COUNT(DISTINCT department_id) FROM employees; -- 计算不重复的部门数SUM - 求和
SELECT SUM(salary) FROM employees; -- 计算薪资总和AVG - 平均值
SELECT AVG(salary) FROM employees; -- 计算平均薪资MIN/MAX - 最小/最大值
SELECT MIN(salary), MAX(salary) FROM employees;MEDIAN - 中位数
SELECT MEDIAN(salary) FROM employees;4.2、统计函数
STDDEV - 标准差
SELECT STDDEV(salary) FROM employees;VARIANCE - 方差
SELECT VARIANCE(salary) FROM employees;4.3、GROUP BY 子句
GROUP BY 用于将结果集按一个或多个列分组:
SELECT department_id, COUNT(*), AVG(salary)
FROM employees
GROUP BY department_id;多列分组
SELECT department_id, job_id, COUNT(*), AVG(salary)
FROM employees
GROUP BY department_id, job_id;4.4、HAVING 子句
HAVING 用于过滤分组后的结果(类似于WHERE,但用于分组后):
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 5000;5、数据排序
5.1、基本排序
单列排序
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary; -- 默认升序(ASC)指定排序方向
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary DESC; -- 降序排列多列排序
SELECT department_id, last_name, salary
FROM employees
ORDER BY department_id ASC, salary DESC;6、多表查询
6.1、基本排序
等值连接:
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;自然连接 (NATURAL JOIN):
SELECT employee_id, last_name, department_name
FROM employees NATURAL JOIN departments;左外连接 (LEFT JOIN):
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;右外连接 (RIGHT JOIN):
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;
-- 包含右表所有记录,左表无匹配则为NULL全外连接 (FULL JOIN):
SELECT e.employee_id, e.last_name, d.department_name
FROM employees e
FULL JOIN departments d ON e.department_id = d.department_id;
-- 包含两表所有记录,无匹配则为NULL交叉连接 (CROSS JOIN)
SELECT e.last_name, d.department_name
FROM employees e
CROSS JOIN departments d;
-- 返回笛卡尔积7、子查询
7.1、子查询基本概念:子查询是嵌套在 SELECT、INSERT、UPDATE、DELETE 或另一个子查询中的查询语句。
子查询分类
单行子查询:返回单行单列结果
多行子查询:返回多行单列结果
多列子查询:返回多列结果
关联子查询:引用外部查询列的子查询
标量子查询:返回单值且可出现在任何表达式位置的子查询
7.2、WHERE 子句中的子查询
1. 单行子查询
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);2. 多行子查询(使用 IN)
SELECT employee_id, last_name, department_id
FROM employees
WHERE department_id IN
(SELECT department_id FROM departments WHERE location_id = 1700);3. 多行子查询(使用 ANY/SOME/ALL)
-- 大于任意一个(ANY/SOME)
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 60);
-- 大于所有(ALL)
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 60);DCL语句
DCL(Data Control Language,数据控制语言)是SQL语言中用于控制数据库访问权限和安全性的语句子集,主要包括权限授予和回收操作。
1. GRANT语句(权限授予)
系统权限授予:
-- 授予用户创建会话的权限
GRANT CREATE SESSION TO scott;
-- 授予用户创建表的权限
GRANT CREATE TABLE TO scott;
-- 授予用户无限表空间配额
GRANT UNLIMITED TABLESPACE TO scott;对象权限授予:
-- 授予对employees表的查询权限
GRANT SELECT ON employees TO scott;
-- 授予对employees表的插入、更新权限
GRANT INSERT, UPDATE ON employees TO scott;
-- 授予对employees表所有操作权限
GRANT ALL ON employees TO scott;
-- 授予权限并允许接收者继续授权
GRANT SELECT ON departments TO scott WITH GRANT OPTION;角色授予:
-- 将CONNECT角色授予用户
GRANT CONNECT TO scott;
-- 将RESOURCE角色授予用户
GRANT RESOURCE TO scott;
-- 将自定义角色授予用户
GRANT hr_manager TO scott;2. REVOKE语句(权限回收)
系统权限回收:
-- 回收创建表的权限
REVOKE CREATE TABLE FROM scott;对象权限回收:
-- 回收对employees表的更新权限
REVOKE UPDATE ON employees FROM scott;
-- 回收所有对象权限
REVOKE ALL ON employees FROM scott;角色回收:
-- 回收RESOURCE角色
REVOKE RESOURCE FROM scott;3. CREATE ROLE语句(角色创建)
-- 创建角色
CREATE ROLE hr_clerk;
-- 为角色授予权限
GRANT SELECT, INSERT ON employees TO hr_clerk;
GRANT SELECT ON departments TO hr_clerk;
-- 将角色授予用户
GRANT hr_clerk TO scott, smith;4. ALTER ROLE语句(角色修改)
-- 为角色设置密码保护
ALTER ROLE hr_manager IDENTIFIED BY secure123;5. SET ROLE语句(角色激活)
-- 激活角色(需要密码)
SET ROLE hr_manager IDENTIFIED BY secure123;
-- 激活多个角色
SET ROLE hr_clerk, hr_manager IDENTIFIED BY secure123;
-- 禁用所有角色
SET ROLE NONE;
-- 激活除指定角色外的所有已授予角色
SET ROLE ALL EXCEPT hr_manager;TCL语句
TCL(Transaction Control Language,事务控制语言)是SQL语言中用于管理数据库事务的语句子集,主要包括事务的提交、回滚和保存点操作。
1. COMMIT(提交事务)
基本语法:
COMMIT;功能说明:
将当前事务中的所有DML操作永久保存到数据库
释放事务占用的所有锁
结束当前事务
使用示例:
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 101;
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 202;
COMMIT; -- 确认转账操作可选子句:
COMMIT WORK; -- WORK关键字可选,与COMMIT等效
COMMIT COMMENT '批量更新用户数据'; -- 添加注释
COMMIT WRITE IMMEDIATE NOWAIT; -- 控制重做日志写入行为2. ROLLBACK(回滚事务)
基本语法:
ROLLBACK;功能说明:
撤销当前事务中的所有DML操作
释放事务占用的所有锁
结束当前事务
使用示例:
BEGIN
INSERT INTO orders VALUES (1001, SYSDATE, 203);
INSERT INTO order_items VALUES (1001, 1, 10, 5);
-- 发现错误
ROLLBACK; -- 撤销整个事务
END;回滚到保存点:
SAVEPOINT sp1;
UPDATE products SET stock = stock - 5 WHERE product_id = 101;
-- 发现错误
ROLLBACK TO sp1; -- 仅回滚到保存点sp13. SAVEPOINT(设置保存点)
基本语法:
SAVEPOINT savepoint_name;功能说明:
在事务中创建标记点
允许部分回滚到指定保存点
保存点在事务提交或回滚后自动清除
使用示例:
BEGIN
UPDATE accounts SET balance = balance - 500 WHERE account_id = 101;
SAVEPOINT after_withdrawal;
UPDATE accounts SET balance = balance + 500 WHERE account_id = 202;
-- 检查发现收款账户错误
ROLLBACK TO after_withdrawal;
UPDATE accounts SET balance = balance + 500 WHERE account_id = 203);
COMMIT;
END;Oracle事务特性
1. ACID特性
原子性(Atomicity):事务是不可分割的工作单位
一致性(Consistency):事务执行前后数据库保持一致状态
隔离性(Isolation):并发事务之间互不干扰
持久性(Durability):事务提交后改变永久有效
2. 事务隔离级别
Oracle支持以下隔离级别:
-- 设置隔离级别(需在事务开始时设置)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 默认级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET TRANSACTION READ ONLY; -- 只读事务3. 自治事务
允许在独立事务中执行特定操作:
CREATE OR REPLACE PROCEDURE log_error (p_msg VARCHAR2) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO error_log VALUES (SYSDATE, p_msg);
COMMIT; -- 独立提交
END;事务管理实践
1. 长事务处理
-- 定期提交大批量操作
BEGIN
FOR i IN 1..10000 LOOP
INSERT INTO big_table VALUES (...);
IF MOD(i, 1000) = 0 THEN
COMMIT; -- 每1000条提交一次
END IF;
END LOOP;
COMMIT;
END;2. 异常处理中的事务控制
BEGIN
SAVEPOINT before_transfer;
BEGIN
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 101;
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 202);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO before_transfer;
DBMS_OUTPUT.PUT_LINE('转账失败: ' || SQLERRM);
END;
END;3. 分布式事务
-- 跨数据库事务
BEGIN
UPDATE accounts@remote_db SET balance = balance - 500 WHERE account_id = 101;
UPDATE local_accounts SET balance = balance + 500 WHERE account_id = 202;
COMMIT; -- 两阶段提交
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;事务监控
1. 查看活动事务
SELECT s.sid, s.serial#, s.username, t.start_time, t.status
FROM v$session s JOIN v$transaction t ON s.saddr = t.ses_addr;2. 查看锁等待
SELECT blocking_session, sid, serial#, wait_class, seconds_in_wait
FROM v$session
WHERE blocking_session IS NOT NULL;3. 查看长时间运行事务
SELECT s.sid, s.username, t.used_ublk, t.start_time
FROM v$session s, v$transaction t
WHERE s.saddr = t.ses_addr
ORDER BY t.used_ublk DESC;注意事项
DDL语句会自动提交当前事务
断开连接时未提交的事务会自动回滚
长时间未提交的事务会导致undo表空间膨胀
分布式事务失败可能需要DBA干预
自治事务中的COMMIT/ROLLBACK不影响主事务
通过合理使用TCL语句,可以确保Oracle数据库事务的完整性和一致性,特别是在复杂的业务操作中,事务控制是保证数据正确性的关键机制。