SQL UNION 子句
SQL UNION 子句/运算符用于将两个或者更多的 SELECT 语句的运算结果组合起来。
在使用 UNION 的时候,每个 SELECT 语句必须有相同数量的选中列、相同数量的列表达式、相同的数据类型,并且它们出现的次序要一致,不过长度不一定要相同。
语法
UNION 子句的基本语法如下所示:
SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]
UNION
SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]
这里的条件可以是任何根据你的需要而设的条件。
示例
考虑如下两张表,(a)CUSTOMERS 表:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
(b)另一张表是 ORDERS 表,如下所示:
+-----+---------------------+-------------+--------+
|OID | DATE | CUSTOMER_ID | AMOUNT |
+-----+---------------------+-------------+--------+
| 102 | 2009-10-08 00:00:00 | 3 | 3000 |
| 100 | 2009-10-08 00:00:00 | 3 | 1500 |
| 101 | 2009-11-20 00:00:00 | 2 | 1560 |
| 103 | 2008-05-20 00:00:00 | 4 | 2060 |
+-----+---------------------+-------------+--------+
现在,让我们用 SELECT 语句将这两张表连接起来:
SQL> SELECT ID, NAME, AMOUNT, DATE
FROM CUSTOMERS
LEFT JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID
UNION
SELECT ID, NAME, AMOUNT, DATE
FROM CUSTOMERS
RIGHT JOIN ORDERS
ON CUSTOMERS.ID = ORDERS.CUSTOMER_ID;
结果如下所示:
+------+----------+--------+---------------------+
| ID | NAME | AMOUNT | DATE |
+------+----------+--------+---------------------+
| 1 | Ramesh | NULL | NULL |
| 2 | Khilan | 1560 | 2009-11-20 00:00:00 |
| 3 | kaushik | 3000 | 2009-10-08 00:00:00 |
| 3 | kaushik | 1500 | 2009-10-08 00:00:00 |
| 4 | Chaitali | 2060 | 2008-05-20 00:00:00 |
| 5 | Hardik | NULL | NULL |
| 6 | Komal | NULL | NULL |
| 7 | Muffy | NULL | NULL |
+------+----------+--------+---------------------+
UNION ALL 子句:
UNION ALL 运算符用于将两个 SELECT 语句的结果组合在一起,重复行也包含在内。
UNION ALL 运算符所遵从的规则与 UNION 一致。
语法:
UNION ALL的基本语法如下:
SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]
UNION ALL
SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]
示例:
考虑如下两张表,(a)CUSTOMERS 表:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
(b)另一张表是 ORDERS 表,如下所示:
+-----+---------------------+-------------+--------+
|OID | DATE | CUSTOMER_ID | AMOUNT |
+-----+---------------------+-------------+--------+
| 102 | 2009-10-08 00:00:00 | 3 | 3000 |
| 100 | 2009-10-08 00:00:00 | 3 | 1500 |
| 101 | 2009-11-20 00:00:00 | 2 | 1560 |
| 103 | 2008-05-20 00:00:00 | 4 | 2060 |
+-----+---------------------+-------------+--------+
结果如下所示:
+------+----------+--------+---------------------+
| ID | NAME | AMOUNT | DATE |
+------+----------+--------+---------------------+
| 1 | Ramesh | NULL | NULL |
| 2 | Khilan | 1560 | 2009-11-20 00:00:00 |
| 3 | kaushik | 3000 | 2009-10-08 00:00:00 |
| 3 | kaushik | 1500 | 2009-10-08 00:00:00 |
| 4 | Chaitali | 2060 | 2008-05-20 00:00:00 |
| 5 | Hardik | NULL | NULL |
| 6 | Komal | NULL | NULL |
| 7 | Muffy | NULL | NULL |
| 3 | kaushik | 3000 | 2009-10-08 00:00:00 |
| 3 | kaushik | 1500 | 2009-10-08 00:00:00 |
| 2 | Khilan | 1560 | 2009-11-20 00:00:00 |
| 4 | Chaitali | 2060 | 2008-05-20 00:00:00 |
+------+----------+--------+---------------------+
另外,还有两个子句(亦即运算法)与 UNION 子句非常相像:
- SQL INTERSECT 子句:用于组合两个 SELECT 语句,但是只返回两个 SELECT 语句的结果中都有的行。
- SQL EXCEPT 子句:组合两个 SELECT 语句,并将第一个 SELECT 语句的结果中存在,但是第二个 SELECT 语句的结果中不存在的行返回。
SQL 索引
索引是一种特殊的查询表,可以被数据库搜索引擎用来加速数据的检索。简单说来,索引就是指向表中数据的指针。数据库的索引同书籍后面的索引非常相像。
例如,如果想要查阅一本书中与某个特定主题相关的所有页面,你会先去查询索引(索引按照字母表顺序列出了所有主题),然后从索引中找到一页或者多页与该主题相关的页面。
索引能够提高 SELECT 查询和 WHERE 子句的速度,但是却降低了包含 UPDATE 语句或 INSERT 语句的数据输入过程的速度。索引的创建与删除不会对表中的数据产生影响。
创建索引需要使用 CREATE INDEX 语句,该语句允许对索引命名,指定要创建索引的表以及对哪些列进行索引,还可以指定索引按照升序或者降序排列。
同 UNIQUE 约束一样,索引可以是唯一的。这种情况下,索引会阻止列中(或者列的组合,其中某些列有索引)出现重复的条目。
CREATE INDEX 命令:
CREATE INDEX命令的基本语法如下:
CREATE INDEX index_name ON table_name;
单列索引:
单列索引基于单一的字段创建,其基本语法如下所示:
CREATE INDEX index_name
ON table_name (column_name);
唯一索引:
唯一索引不止用于提升查询性能,还用于保证数据完整性。唯一索引不允许向表中插入任何重复值。其基本语法如下所示:
CREATE UNIQUE INDEX index_name
on table_name (column_name);
聚簇索引:
聚簇索引在表中两个或更多的列的基础上建立。其基本语法如下所示:
CREATE INDEX index_name
on table_name (column1, column2);
创建单列索引还是聚簇索引,要看每次查询中,哪些列在作为过滤条件的 WHERE 子句中最常出现。
如果只需要一列,那么就应当创建单列索引。如果作为过滤条件的 WHERE 子句用到了两个或者更多的列,那么聚簇索引就是最好的选择。
隐式索引:
隐式索引由数据库服务器在创建某些对象的时候自动生成。例如,对于主键约束和唯一约束,数据库服务器就会自动创建索引。
DROP INDEX 命令:
索引可以用 SQL DROP 命令删除。删除索引时应当特别小心,数据库的性能可能会因此而降低或者提高。
其基本语法如下:
DROP INDEX index_name;
什么时候应当避免使用索引?
尽管创建索引的目的是提升数据库的性能,但是还是有一些情况应当避免使用索引。下面几条指导原则给出了何时应当重新考虑是否使用索引:
- 小的数据表不应当使用索引;
- 需要频繁进行大批量的更新或者插入操作的表;
- 如果列中包含大数或者 NULL 值,不宜创建索引;
- 频繁操作的列不宜创建索引。
SQL 使用视图
视图无非就是存储在数据库中并具有名字的 SQL 语句,或者说是以预定义的 SQL 查询的形式存在的数据表的成分。
视图可以包含表中的所有列,或者仅包含选定的列。视图可以创建自一个或者多个表,这取决于创建该视图的 SQL 语句的写法。
视图,一种虚拟的表,允许用户执行以下操作:
- 以用户或者某些类型的用户感觉自然或者直观的方式来组织数据;
- 限制对数据的访问,从而使得用户仅能够看到或者修改(某些情况下)他们需要的数据;
- 从多个表中汇总数据,以产生报表。
SQL 事务
事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序自动执行。
事务实际上就是对数据库的一个或者多个更改。当你在某张表上创建更新或者删除记录的时,你就已经在使用事务了。控制事务以保证数据完整性,并对数据库错误做出处理,对数据库来说非常重要。
实践中,通常会将很多 SQL 查询组合在一起,并将其作为某个事务一部分来执行。
事务的属性:
事务具有以下四个标准属性,通常用缩略词 ACID 来表示:
- 原子性:保证任务中的所有操作都执行完毕;否则,事务会在出现错误时终止,并回滚之前所有操作到原始状态。
- 一致性:如果事务成功执行,则数据库的状态得到了进行了正确的转变。
- 隔离性:保证不同的事务相互独立、透明地执行。
- 持久性:即使出现系统故障,之前成功执行的事务的结果也会持久存在。
事务控制:
有四个命令用于控制事务:
- COMMIT:提交更改;
- ROLLBACK:回滚更改;
- SAVEPOINT:在事务内部创建一系列可以 ROLLBACK 的还原点;
- SET TRANSACTION:命名事务;
COMMIT 命令:
COMMIT 命令用于保存事务对数据库所做的更改。
COMMIT 命令会将自上次 COMMIT 命令或者 ROLLBACK 命令执行以来所有的事务都保存到数据库中。
COMMIT 命令的语法如下所示:
COMMIT;
示例:
考虑 CUSTOMERS 表,表中的记录如下所示:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
下面的示例将会删除表中 age=25 的记录,然后将更改提交(COMMIT)到数据库中。
SQL> DELETE FROM CUSTOMERS
WHERE AGE = 25;
SQL> COMMIT;
上述语句将会从表中删除两行记录,再执行 SELECT 语句将会得到如下结果:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
ROLLBACK 命令:
ROLLBACK 命令用于撤销尚未保存到数据库中的事务。
ROLLBACK 命令只能撤销自上次 COMMIT 命令或者 ROLLBACK 命令执行以来的事务。
ROLLBACK 命令的语法如下所示:
ROLLBACK;
示例:
考虑 CUSTOMERS 表,表中的记录如下所示:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
下面的示例将会从表中删除所有 age=25 的记录,然后回滚(ROLLBACK)对数据库所做的更改。
SQL> DELETE FROM CUSTOMERS
WHERE AGE = 25;
SQL> ROLLBACK;
结果是删除操作并不会对数据库产生影响。现在,执行 SELECT 语句将会得到如下结果:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
SAVEPOINT 命令:
SAVEPOINT 是事务中的一个状态点,使得我们可以将事务回滚至特定的点,而不是将整个事务都撤销。
SAVEPOINT 命令的记录如下所示:
SAVEPOINT SAVEPOINT_NAME;
该命令只能在事务语句之间创建保存点(SAVEPOINT)。ROLLBACK 命令可以用于撤销一系列的事务。
回滚至某一保存点的语法如下所示:
ROLLBACK TO SAVEPOINT_NAME;
下面的示例中,你计划从 CUSTOMERS 表中删除三条不同的记录,并在每次删除之前创建一个保存点(SAVEPOINT),从而使得你可以在任何任何时候回滚到任意的保存点,以恢复数据至其原始状态。
示例:
考虑 CUSTOMERS 表,表中的记录如下所示:
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
操作序列如下所示:
SQL> SAVEPOINT SP1;
Savepoint created.
SQL> DELETE FROM CUSTOMERS WHERE ID=1;
1 row deleted.
SQL> SAVEPOINT SP2;
Savepoint created.
SQL> DELETE FROM CUSTOMERS WHERE ID=2;
1 row deleted.
SQL> SAVEPOINT SP3;
Savepoint created.
SQL> DELETE FROM CUSTOMERS WHERE ID=3;
1 row deleted.
现在,三次删除操作已经生效了,如果此时你改变主意决定回滚至名字为 SP2 的保存点,由于 SP2 于第一次删除操作之后创建,所以后两次删除操作将会被撤销。
SQL> ROLLBACK TO SP2;
Rollback complete.
注意,由于你将数据库回滚至 SP2,所以只有第一次删除真正起效了:
SQL> SELECT * FROM CUSTOMERS;
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 3 | kaushik | 23 | Kota | 2000.00 |
| 4 | Chaitali | 25 | Mumbai | 6500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 6 | Komal | 22 | MP | 4500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
+----+----------+-----+-----------+----------+
6 rows selected.
RELEASE SAVEPOINT 命令:
RELEASE SAVEPOINT 命令用于删除先前创建的保存点。
RELEASE SAVEPOINT 的语法如下所示:
RELEASE SAVEPOINT SAVEPOINT_NAME;
保存点一旦被释放,你就不能够再用 ROLLBACK 命令来撤销该保存点之后的事务了。
SET TRANSACTION 命令:
SET TRANSACTION 命令可以用来初始化数据库事务,指定随后的事务的各种特征。
例如,你可以将某个事务指定为只读或者读写。
SET TRANSACTION 命令的语法如下所示:
SET TRANSACTION [ READ WRITE | READ ONLY ];