zoukankan      html  css  js  c++  java
  • 临时表、表变量、公用表表达式【转】

    MySQL、SQL SERVER提供了三种方法临时存储结果集,分别是临时表、表变量和公用表表达式。

    临时表

    临时表需要在临时数据库TempDB中通过I/O操作来创建表结构,一旦用户退出SQL Server环境,临时表会自动被删除。临时表有两种,一种是本地临时表,仅在当前会话中可见,前缀是【#】;一种是全局临时表,在所有会话中都可见,前缀是【##】。

    临时表的优缺点

    临时表的优点是能够和普通的物理表一样长久存储数据,可以建立索引,能存储大量的数据。

    临时表的缺点是使用不方便,在使用之后还要手动通过DROP语句去删除,否则会一直存在,直到此次数据库连接关闭。

    本地临时表与本地临时表的特点

    1.本地临时表就是用户在创建表的时候添加了【#】前缀的表,其特点是根据数据库连接独立。只有创建本地临时表的数据库连接有表的访问权限,其它连接不能访问该表。

    2.不同的数据库连接中,创建的本地临时表虽然名字相同,但是这些表之间相互并不存在任何关系;在SQL Server中,通过特别的命名机制保证本地临时表在数据库连接上的独立性。

    3.真正的临时表利用了数据库临时表空间,由数据库系统自动进行维护,因此节省了表空间。并且由于临时表空间一般利用虚拟内存(其实还是硬盘),大大减少了硬盘的I/O次数,因此也提高了系统效率。

    4.临时表在事务完毕或会话完毕数据自动清空,不必记得用完后删除数据。

    -- 创建临时表方法一,SELECT INTO ... FROM ...
    SELECT INTO #TEMP_USERS FROM USERS;
    
    -- 创建临时表方法二,CREATE TABLE ...
    CREATE TABLE #TEMP_USERS(ID VARCHAR, NAME VARCHAR);
    INSERT INTO #TEMP_USERS SELECT ID, NAME FROM USERS;
    
    -- 使用临时表
    SELECT * FROM #TEMP_USERS;
    
    -- 删除临时表(建议是使用完立即删除)
    DROP TABLE #TEMP_USERS;

    全局临时表与全局临时表的特点

    全局临时表的名称以两个数字符号 【##】 打头,创建后对任何数据库连接都是可见的,当所有引用该表的数据库连接从SQL Server断开时被删除。

    -- 创建临时表方法一,SELECT INTO ... FROM ...
    SELECT INTO ##TEMP_USERS FROM USERS;
    
    -- 创建临时表方法二,CREATE TABLE ...
    CREATE TABLE ##TEMP_USERS(ID VARCHAR, NAME VARCHAR);
    INSERT INTO ##TEMP_USERS SELECT ID, NAME FROM USERS;
    
    -- 使用临时表
    SELECT * FROM ##TEMP_USERS;
    
    -- 删除临时表(建议是使用完立即删除)
    DROP TABLE ##TEMP_USERS;

    表变量

    表变量在内存/TempDB中以表结构的形式存在,其定义与普通的变量一致,使用上和普通表类似,可以不需要产生磁盘I/O。

    表变量的优点

    1.与其他变量的定义一样,表变量具有良好的定义范围,并会被自动清除。

    2.在存储过程中使用表变量会减少存储过程重新编译的发生。

    3.表变量需要更少的锁请求和日志资源。

    4.可以在表变量上使用UDF、UDDT和XML。

    表变量的缺点

    1.在表变量上没有统计信息,查询优化器根据固定的预估值来选择执行计划,在数据很多的情况下,会导致查询优化器选择很差的执行计划。

    2.不能直接在表变量上创建索引,但可以通过创建约束(主键、唯一)来建立索引。

    3.在DECLARE后,不能再对表变量进行更改。

    4.不能对表变量执行INSERT EXEC或SELECT INTO语句。

    5.不能通过EXEC或SP_EXECUTESQL来执行牵涉到表变量的动态SQL语句,但如果表变量是在动态SQL语句内定义的,则可以。

    表变量的使用

    如果表的行数非常多,使用表变量会十分浪费资源。一般建议是对于行数较少的情况下(小于1000行)可以使用表变量;如果行数很多(有几万行)可以使用临时表。

    -- 定义表变量
    DECLARE @TEMP_USERS TABLE(ID VARCHAR, NAME VARCHAR);
    -- 往表变量中插入数据
    INSERT INTO @TEMP_USERS SELECT ID, NAME FROM USERS;
    -- 使用表变量
    SELECT * FROM @temp;

    要注意的是,表变量的有效范围是整个批处理、程序或函数的处理过程。当在一段程序中发出GO命令的时候,表变量就会被删除,不再有效了。

    公用表表达式

    公用表表达式(CTE,Common Table Expression)的定义是在内存中保存的临时存储结果集对象,不会产生磁盘I/O,也不需要按照表变量那样定义,使用的方法则和普通表类似。

    公用表表达式的注意事项

    1.WITH AS-做子查询部分(subquery factoring)。

    2.如果WITH AS所以定的表名被调用两次以上,则优化器会自动将WITH AS所获取的数据放入临时表里,如果只是被调用一次,则不会。

    3.WITH AS可以被紧跟着的一条SQL语句使用多次,但不能被紧跟着的多条SQL语句使用。

    4.如果将CTE用在属于批处理的一部分的语句中,那么在它之前的语句必须以分号结尾。

    公用表表达式的定义语法

    公用表表达式的定义包括三个部分,分别是表达式的名称(expression_Name),列名列表(column_name)和定义CTE结果集的SELECT查询语句(cte_query_definition)。

    WITH expression_name [(column_name [,...n] )] AS ( 
        cte_query_definition
    )

    公用表表达式的优点

    根据微软对CTE好处的描述,可以归结为四点:

    1.当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁。

    2.GROUP BY语句可以直接作用于子查询所得的标量列.

    3.可以在一个语句中多次引用公用表表达式(CTE)。

    4.可以使用递归。

    非递归公用表表达式

    WITH TEMP_USERS AS (
        SELECT * FROM USERS
    )
    SELECT * FROM TEMP_USERS;

    可以在接下来的一条语句中多次引用。

    WITH TEMP_USERS AS (
        SELECT * FROM USERS
    )
    SELECT * FROM TEMP_USERS WHERE NAME LIKE '杨%'
    UNION
    SELECT * FROM TEMP_USERS WHERE NAME LIKE '%静';

    不可以多条语句引用。

    WITH TEMP_USERS AS (
        SELECT * FROM USERS
    )
    SELECT * FROM TEMP_USERS;
    SELECT * FROM TEMP_USERS; -- 报错,找不到该表

    可以一次定义多个CTE,用逗号隔开。

    WITH
    TEMP_USERS AS (
        SELECT * FROM USERS
    ),
    TEMP_ORGS AS (
        SELECT * FROM ORGS
    )
    SELECT * FROM TEMP_USERS AS A
        INNER JOIN TEMP_ORGS AS B ON A.ORG_ID = B.ID;

    递归公用表表达式

    递归CTE定义至少必须包含两个CTE查询定义,一个是定位点成员,一个是递归成员。可以定义多个定位点成员和递归成员,但必须将所有定位点成员查询定义置于第一个递归成员定义之前。所有CTE查询定义都是定位点成员,但它们引用CTE本身时除外。定位点成员必须与以下集合运算符之一结合使用:UNION ALL、UNION、INTERSECT或EXCEPT。 在最后一个定位点成员和第一个递归成员之间,以及组合多个递归成员时,只能使用UNION ALL集合运算符。

    WITH TEMP_ORGS(ID, NAME, PID, LEVEL) AS (
        -- 基本语句(递归起始点)
        SELECT ID, NAME, PID, 0 AS LEVEL
        FROM ORGS
        WHERE PID IS NULL
        
        UNION ALL
        
        -- 递归语句
        SELECT A.ID, A.NAME, A.PID, B.LEVEL + 1 AS LEVEL 
        FROM ORGS AS A
            INNER JOIN TEMP_ORGS AS B ON A.PID = B.ID -- 递归调用
    )
    SELECT * FROM TEMP_ORGS
    OPTION(MAXRECURSION 2); -- 指定最大递归次数为2

    这里的OPTION是可选的,通过指定MAXRECURSION参数可以用来限制递归的最大次数。

  • 相关阅读:
    【记录】20060430 11:30:00 本Blog访问量突破100000 !
    ESFramework介绍之(24)―― 日志记录IEsbLogger
    ESFramework介绍之(20)―― 插件自动升级
    ESFramework介绍之(21)-- Tcp组件接口ITcp介绍
    ESFramework介绍之(17)―― 支持漫游用户和跨区域功能请求
    python标准库学习9
    python标准库学习5 bisect — Array bisection algorithm
    C++中四种显示类型转换总结
    BeautifulSoup学习笔记
    jdbc连接数据库(水文)
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/13575941.html
Copyright © 2011-2022 走看看