从可能不存在的表中选择

时间:2018-04-27 20:32:02

标签: oracle plsql

我们有一个问题,需要一个糟糕的黑客来解决。让我给你一些背景信息:

我们有一个应用程序在卸载/重新安装它时会覆盖客户配置设置。它安装时使用默认值,覆盖客户输入的任何设置。

管理层的解决方案是创建两个脚本,每个步骤一个:

  1. 在卸载应用程序之前,创建一个临时表并将配置设置复制到其中。

  2. 重新安装应用后,将临时表中的值复制回原始表格以保留其设置。

  3. 我不太喜欢他们的解决方案,但我必须坚持下去。

    我有第1步,但我在处理第二个脚本(第2步)的情况时遇到问题,而没有先运行第一个脚本(步骤1)。

    实质上,当第二个脚本编译时,如果不同部门中的其他人忘记运行第一个脚本,则临时表将不存在。

    这是我目前用于第二个脚本的代码。

    DECLARE
        lvnTableExists              NUMBER(1);
        lvbTempTableCopied          BOOLEAN;
        lvsTempTable                VARCHAR2(21) := 'TEMP_TABLE';
    BEGIN
        -- CalcTypVarValue Table Copy
        SELECT COUNT(*)
        INTO   lvnTableExists
        FROM   ALL_TABLES x
        WHERE  x.Table_Name = lvsTempTable ;
    
        IF lvnTableExists = 1 THEN
            FOR CalcRow IN (SELECT * FROM Temp_Table) LOOP -- Temp_Table will not exist if first script didn't run, causing a compile error
                UPDATE SomeOtherTable c
                SET    c.foo= CalcRow.foo,
                       c.bar= CalcRow.bar,
                       c.DateLastMaint = SYSDATE
                WHERE  c.bob= CalcRow.bob
                AND    c.bill= CalcRow .bill;
            END LOOP;
            lvbTempTableCopied    := TRUE;
        ELSE
            lvbTempTableCopied    := FALSE;
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
        ...
        ...
    

    我的问题是,如果Temp_Table根本不存在,那么我将收到编译时错误,因此脚本根本不会运行。我需要它才能运行,所以如果基于lvbTempTableCopied的表不存在,我可以就是否做其他事情采取行动。

    我听说过用FOR CalcRow IN (EXECUTE IMMEDIATE 'SELECT * FROM ' || lvsTempTable)之类的东西绕过它,但我不能在FOR IN LOOP之内使用它。

    我如何使用EXECUTE IMMEDIATE来绕过编译时错误?

1 个答案:

答案 0 :(得分:2)

您可以使用REF CURSOR动态执行此操作,请参阅下面的示例代码,

DECLARE
    TYPE cur_typ IS REF CURSOR;
    c cur_typ;
    v_table_exists VARCHAR2(1);
    type temp1_rec is record (col1 VARCHAR2(100), col2 VARCHAR2(100));
    v_temp temp1_rec;
BEGIN
    SELECT 'Y'
      INTO v_table_exists
      FROM all_tables
     WHERE table_name = 'TEMP1';

     --dynamic query with parameters
     OPEN c FOR 'SELECT col1, col2 FROM temp1 WHERE :param1=:param2' USING 'PARAM1', 'PARAM1' ;
     LOOP
         FETCH c INTO v_temp;
         EXIT WHEN c%NOTFOUND;
         DBMS_OUTPUT.PUT_LINE(v_temp.col1);
     END LOOP;  
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        NULL;
END;
/

CREATE TABLE TEMP1
(COL1 VARCHAR2(100),
 col2 VARCHAR2(100));

INSERT INTO temp1
VALUES('123123123asdfasdfsfa', 'JHASDKLFJLASDFLAS');