临时表的寿命

时间:2009-12-02 18:00:03

标签: sql database informix temp-tables

我有以下程序:

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

5 个答案:

答案 0 :(得分:4)

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

如果存储过程因表已经存在而失败,则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 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;

答案 1 :(得分:3)

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

答案 2 :(得分: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;

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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相同。