跳转到内容

结构化查询语言/临时表

来自维基教科书,开放的书籍,面向开放的世界



常规表是用来存储数据较短或较长时间的容器,并将数据提供给各种进程。相反,有时需要处理短时间内且仅用于本地目的的数据。临时表提供了解决方案。它们与常规表一样,遵循 SQL 语法。

所有临时表的共同特征是,每个会话(连接)都会获得临时表的独立副本,而不会对其他会话产生任何副作用。这会导致每个会话只能看到之前插入的数据。数据在不同会话之间不会共享,即使它们在同一时间使用相同的表名。每个会话都在不同的副本上进行操作。另一个共同特征是,当会话终止时,临时表的所有数据都会自动被丢弃。不需要显式 DELETE 或 DROP TABLE。

临时表的概念类似于编程语言中记录数组的概念。它相对于数组的优势是可以使用 SQL 中所有已知的 DML 语句,例如:如果您需要一些中间数据,您可以从常规表中检索它并使用一个 Insert+Subselect 命令将其存储在临时表中。它相对于常规表的优势是,可以节省日志记录和锁定的开销。

临时表有三种略微不同的类型

  • 全局临时表
  • 本地临时表
  • 声明式本地临时表。
CREATE  GLOBAL TEMPORARY TABLE <table_name> (...) [ ON COMMIT { PRESERVE | DELETE } ROWS ];
CREATE  LOCAL  TEMPORARY TABLE <table_name> (...) [ ON COMMIT { PRESERVE | DELETE } ROWS ];
DECLARE LOCAL  TEMPORARY TABLE <table_name> (...) [ ON COMMIT { PRESERVE | DELETE } ROWS ];

如果使用短语“ON COMMIT DELETE ROWS”,则数据会在每次 COMMIT 命令执行时自动被丢弃,否则会在会话结束时(或使用 DELETE 命令)被丢弃。

全局临时表 (GTT)

[编辑 | 编辑源代码]

如果创建 GTT,它的定义将成为数据库的一部分,即使在定义会话结束之后也是如此。使用数据库的其他会话将看到此表定义作为架构的一部分。GTT 可以与常规表同时定义。应用程序可以使用现有的 GTT 或创建自己的 GTT。到目前为止,GTT 与常规表没有区别。区别在于数据。与所有临时表一样,每个会话都会获得表的独立副本,并且无法访问其他会话的数据。如果会话终止,表中的所有数据都会自动被丢弃。

一个典型的用例是一个应用程序,它需要一个关于自身活动的临时协议,例如成功操作、异常等,以便稍后执行恢复活动。这些信息对其他会话来说并不重要。此外,它可以在事务结束时或会话结束时被删除。

另一个用例是一个应用程序,它存储一个中间结果集,并迭代该结果集的行以根据列值执行操作。

-- The table may be defined by a different session long time before.
CREATE GLOBAL TEMPORARY TABLE temp1 (
  ts       TIMESTAMP,
  action   CHAR(100),
  state    CHAR(50)
)
ON COMMIT PRESERVE ROWS;
--
-- Insert some data
INSERT INTO temp1 VALUES (current_timestamp, 'node-1-request sended.', 'OK');
INSERT INTO temp1 VALUES (current_timestamp, 'node-2-request sended.', 'OK');
INSERT INTO temp1 VALUES (current_timestamp, 'node-1-answer received.', 'Failed');
INSERT INTO temp1 VALUES (current_timestamp, 'node-2-answer received.', 'OK');
SELECT count(*) FROM temp1 WHERE state = 'OK';
...
COMMIT; 
SELECT count(*) FROM temp1; -- In this example, all rows should have survived the COMMIT command
-- After a disconnect from the database and establishing a new session the table exists and is empty.

本地临时表 (LTT)

[编辑 | 编辑源代码]

LTT 的定义永远不会超过会话的持续时间。同样适用于它的数据,这与所有临时表的行为一致。因此,每个会话都必须在存储任何数据之前定义自己的 LTT。多个会话可以同时使用相同的表名,而不会相互影响,这再次与所有临时表的行为一致。

-- The table must be defined by the same session (connection), which stores data into it.
CREATE LOCAL TEMPORARY TABLE temp2 (
  ts       TIMESTAMP,
  action   CHAR(100),
  state    CHAR(50)
)
ON COMMIT PRESERVE ROWS;
-- After a disconnect from the database and establishing a new session, the table will not exist.

SQL 标准区分 SQL 会话和 SQL 会话内的模块。它规定 LTT 只能在创建表的模块内可见。这些表不会在同一 SQL 会话的不同模块之间共享。但是 LTT 的定义会出现在 DBMS 的信息模式中。

声明式本地临时表 (DLTT)

[编辑 | 编辑源代码]

DLTT 的主要概念与 LTT 非常相似。区别在于,与 LTT 的定义相反,DLTT 的定义不会出现在 DBMS 的信息模式中。它只被定义它的模块所知。可以将 DLTT 想象成某种模块局部变量。

-- The declaration must be defined by the same module which stores data into the table.
DECLARE LOCAL TEMPORARY TABLE temp3 (
  ts       TIMESTAMP,
  action   CHAR(100),
  state    CHAR(50)
)
ON COMMIT PRESERVE ROWS;
-- After a disconnect from the module and entering the module again, the declaration will not exist.

实现提示

[编辑 | 编辑源代码]

MySQL

  • 省略关键字 LOCAL/GLOBAL 和 ON COMMIT 短语。临时表始终是 LOCAL,并且 ON COMMIT 始终以 PRESERVE ROWS 的方式工作。
  • GTT 和 DLTT 不受支持。

Oracle

  • LTT 和 DLTT 不受支持。


华夏公益教科书