【问题标题】:life span of temp table临时表的寿命
【发布时间】:2010-12-22 12:36:13
【问题描述】:

我有以下程序:

CREATE PROCEDURE foo ()
    SELECT * FROM fooBar INTO TEMP tempTable;

    -- do something with tempTable here

    DROP TABLE tempTable;
END PROCEDURE;

如果在调用 DROP TABLE 之前出现异常会发生什么? foo 退出后 tempTable 还会存在吗?

如果是这样,下次调用 foo 时可能会失败,因为 tempTable 已经存在。应该怎么处理。

编辑:我使用的是 informix 11.5

【问题讨论】:

    标签: sql database informix temp-tables


    【解决方案1】:

    According to the documentation,会话结束时会删除临时表。

    【讨论】:

    • 我想,我担心的是会话在连接关闭时结束(对吗?)。因此,如果在连接关闭之前多次调用 foo,并且对 foo 的第一次调用抛出异常并且没有清理临时表,那么下一次调用 foo 将失败,因为临时表已经存在。编写代码以防止这种情况的最佳实践是什么。我们是否需要检查临时表是否存在并删除它?
    • 我在创建和删除之前输入了“检查表是否存在”代码进行检查。 Informix 是否有一个临时表结构,其中一个表只能由特定会话看到? SQL Server 具有此功能。
    【解决方案2】:

    正如其他人所说,临时表会持续存在,直到您明确删除它们或会话结束。

    如果存储过程因表已存在而失败,SPL 将生成异常。 您可以通过添加 ON EXCEPTION 子句来处理异常——但您正在输入 SPL 中比较巴洛克的部分之一,即存储过程语言。

    这是您的存储过程的轻微修改版本 - 生成除以零异常 (SQL -1202):

    CREATE PROCEDURE foo ()
        define i integer;
        SELECT * FROM 'informix'.systables INTO TEMP tempTable;
    
        -- do something with tempTable here
        let i = 1 / 0;
    
        DROP TABLE tempTable;
    END PROCEDURE;
    
    execute procedure foo();
    SQL -1202: An attempt was made to divide by zero.
    
    execute procedure foo();
    SQL -958: Temp table temptable already exists in session.
    

    这表明第一次通过代码执行了 SELECT,创建了表,然后运行了除以零的错误。但是,第二次 SELECT 失败,因为临时表已经存在,因此出现了不同的错误消息。

    drop procedure foo;
    CREATE PROCEDURE foo()
        define i integer;
    
        BEGIN
            ON EXCEPTION
                DROP TABLE tempTable;
                SELECT * FROM 'informix'.systables INTO TEMP tempTable;
            END EXCEPTION WITH RESUME;
            SELECT * FROM 'informix'.systables INTO TEMP tempTable;
        END;
    
        -- do something with tempTable here
        let i = 1 / 0;
    
        DROP TABLE tempTable;
    END PROCEDURE;
    

    BEGIN/END 块将异常处理限制为捕获的语句。如果没有 BEGIN/END,异常处理会覆盖整个过程,也会对除以零错误做出反应(因此让 DROP TABLE 工作并且过程似乎运行成功)。

    注意此时 temptable 仍然存在:

    + execute procedure foo();
    SQL -1202: An attempt was made to divide by zero.
    + execute procedure foo();
    SQL -1202: An attempt was made to divide by zero.
    

    这表明该过程不再失败,因为临时表存在。

    您可以通过以下方式将 ON EXCEPTION 块限制为选定的错误代码(-958 似乎对这个错误代码可行):

    ON EXCEPTION IN (-958) ...
    

    请参阅 IBM Informix Guide to SQL:语法手册,第 3 章“SPL 语句”。

    请注意,Informix 11.70 在 CREATE 和 DROP 语句中添加了“IF EXISTS”和“IF NOT EXISTS”子句。因此,您可以使用修改后的DROP TABLE 语句:

    DROP TABLE IF EXISTS tempTable;
    

    因此,对于 Informix 11.70 或更高版本,编写过程的最简单方法是:

    DROP PROCEDURE IF EXISTS foo;
    
    CREATE PROCEDURE foo()
        define i integer;
        DROP TABLE IF EXISTS tempTable;
    
        SELECT * FROM 'informix'.systables INTO TEMP tempTable;
    
        -- do something with tempTable here
        let i = 1 / 0;
    
        DROP TABLE tempTable;  -- Still a good idea
    END PROCEDURE;
    

    你也可以使用它,但是你会得到之前的过程定义,不管它是什么,它可能不是你所期望的。

    CREATE PROCEDURE IF NOT EXISTS foo()
        define i integer;
        DROP TABLE IF EXISTS tempTable;
    
        SELECT * FROM 'informix'.systables INTO TEMP tempTable;
    
        -- do something with tempTable here
        let i = 1 / 0;
    
        DROP TABLE tempTable;  -- Still a good idea
    END PROCEDURE;
    

    【讨论】:

    • @Jonathan 我使用了您在此处建议的变体。我提交了我用作答案的内容。如果您在该 spl/sql 上有任何 cmets,请告诉我。
    【解决方案3】:

    我终于使用了 Jonathan 和 RET 解决方案的变体:

    CREATE PROCEDURE foo ()
        ON EXCEPTION IN (-206)
        END EXCEPTION WITH RESUME;
    
        DROP TABLE tempTable;    
    
        SELECT * FROM fooBar INTO TEMP tempTable;
    
        -- do something with tempTable here
    
        DROP TABLE tempTable;
    END PROCEDURE;
    

    【讨论】:

    • 你在这里得到的——删除表但如果它不存在则忽略错误——是一个很好的方法。在一般情况下,临时表在运行之前和完成之后都会丢失。可以调整异常的范围,但这应该可以正常工作。
    • 请注意,现代 Informix 在 DROP TABLE 等语句中支持 IF EXISTS 和 IF NOT EXISTS 子句。因此,这些天,您可能会写:DROP TABLE IF EXISTS tempTable; 如果该表存在(并且您有权限等),它将删除该表,如果该表不存在,则不执行任何操作。
    【解决方案4】:

    是的,临时表仍然存在。根据定义,临时表具有创建它们的会话的生命周期,除非显式删除。

    临时表只能由创建它的会话看到,并且多个用户并行运行同一过程没有任何障碍。如果任何用户正在运行该过程,Adam 测试临时表是否存在的答案将返回非零结果。您需要测试拥有临时表的会话是否也是当前会话。鉴于这个问题在存储过程的范围内,添加显式 DROP 并包含在一些异常处理中可能会更简单。

    【讨论】:

    • 我假设你的意思是这样的: CREATE PROCEDURE droptempTtable() ON EXCEPTION IN (-206) END EXCEPTION;删除表临时表;结束程序;你知道有什么方法可以指定表名,使这个过程通用吗?
    【解决方案5】:
    SELECT count(*) 
    INTO w_count 
    FROM sysmaster:systabnames s,sysmaster:systabinfo i
    WHERE i.ti_partnum = s.partnum
    AND sysmaster:BITVAL(i.ti_flags,'0x0020') = 1
    AND s.tabname = 'tempTable' ;
    

    如果 w_count 为 1,则在 SELECT ... INTO 之前删除表。与 DROP TABLE 相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 2011-01-31
      • 2011-06-07
      相关资源
      最近更新 更多