【问题标题】:PL/SQL: Creation and usage of a temporary table in scriptPL/SQL:在脚本中创建和使用临时表
【发布时间】:2022-01-12 09:48:06
【问题描述】:

在 Oracle 19c DB 上,我需要对客户进行抽样,同时保持统一分布以模拟客户的移动。 有(故意)多行具有相同的客户,但将 adderssses 更改为模型移动。因此,对于采样,我需要先分组。

现在我得到的是,对于 SAMPLE 子句,源必须具体化。因此,在 PL/SQL 脚本中,我生成了一个临时表,之后我想将其与 SAMPLE 一起使用。 但是之后即使是简单的 SELECT INTO 也不起作用。

set SERVEROUT on;
DECLARE
    v_cust_name VARCHAR2(100);
    cmd_creation VARCHAR2(500):='CREATE PRIVATE TEMPORARY TABLE ORA$PTT_temp_cust AS(
        SELECT cust_id, MIN(name) as name
        FROM customers
        GROUP BY cust_id)';
BEGIN
    
    EXECUTE IMMEDIATE cmd_creation;
    dbms_output.put_line('temp created');
    
    SELECT name 
    INTO v_cust_name
    FROM (SELECT * 
        FROM ORA$PTT_temp_cust SAMPLE(5))
    WHERE ROWNUM =1;
        
    EXECUTE IMMEDIATE 'DROP TABLE ORA$PTT_temp_cust';
    dbms_output.put_line('temp dropped');
END;

我得到的是这个

ORA-06550: line 15, column 18:
PL/SQL: ORA-00942: table or view does not exist

表被创建。当我只为创建执行 String 而没有其他事情时,我已经走到了这一步。然后我可以从不同的点访问所需脚本中的表。 这和编译有关系吗?有什么不同的方法可以解决这个问题吗?

【问题讨论】:

  • 你执行了 nothing PL/SQL 没有编译
  • 此外,没有理由即时创建“临时”表。不要像对待 mssql 一样对待 oracle。查看global temporary table
  • OP 正在使用 Oracle 中引入的 PRIVATE TEMPORARY 表 @EdStevens 来满足人们过去在其他数据库中这样做的习惯;)
  • @MarmiteBomber - 是的,但这并不是最好的方法。如果 OP 将创建一个 GTT(一次),那么他与 PT 表的问题将不复存在,并且他不必求助于邪恶的动态 SQL 和所有其他随之而来的问题。
  • @EdStevens 将尝试使用 GTT,感谢您的提示!

标签: sql oracle plsql oracle19c


【解决方案1】:

您的 PL/SQL Block simple 无法编译,因为您查询的表在编译时不存在

您必须使用execute immediate 执行事件查询

简化示例

DECLARE
    v_cust_name VARCHAR2(100);
    cmd_creation VARCHAR2(500):='CREATE PRIVATE TEMPORARY TABLE ORA$PTT_temp_cust  AS select * from dual';

BEGIN
    
    EXECUTE IMMEDIATE cmd_creation;
    dbms_output.put_line('temp created');
    
    EXECUTE IMMEDIATE 'SELECT DUMMY  FROM ORA$PTT_temp_cust' INTO v_cust_name;
    dbms_output.put_line('name' || v_cust_name);
        
    EXECUTE IMMEDIATE 'DROP TABLE ORA$PTT_temp_cust';
    dbms_output.put_line('temp dropped');
END;
/

在您的设置中可能导致ORA-00942: table or view does not exist 的另一个警告是您在脚本中执行commit

ON COMMIT 子句的默认定义是DROP DEFINITION,所以你必须使用

CREATE PRIVATE TEMPORARY TABLE ORA$PTT_temp_cust 
ON COMMIT PRESERVE DEFINITION 
...

【讨论】:

    【解决方案2】:

    动态 SQL 是邪恶的。您使用动态 SQL(您的第一个 execute immediate)创建表这一事实并不意味着 Oracle “预测”您实际上会成功并“假定”以下语句是正确的。不,该表还不存在,因此必须将所有内容移至动态 SQL。

    类似这样(忽略我使用的表和列名以及全局与私有临时表的更改;这是 11gXE):

    SQL> DECLARE
      2     v_cust_name   VARCHAR2 (100);
      3     cmd_creation  VARCHAR2 (500)
      4                      := 'CREATE global TEMPORARY TABLE PTT_temp_cust AS
      5          SELECT empno, MIN(ename) as name
      6          FROM emp
      7          GROUP BY empno';
      8  BEGIN
      9     EXECUTE IMMEDIATE cmd_creation;
     10
     11     EXECUTE IMMEDIATE '
     12      SELECT max(name)
     13      FROM (SELECT *
     14          FROM PTT_temp_cust SAMPLE(5))
     15      WHERE ROWNUM = 1'
     16        INTO v_cust_name;
     17
     18     EXECUTE IMMEDIATE 'DROP TABLE PTT_temp_cust';
     19
     20     DBMS_OUTPUT.put_line ('Result = ' || v_cust_name);
     21  END;
     22  /
    Result =
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    虽然我没有得到任何结果 - 但你应该(至少,我希望如此)。

    【讨论】:

      猜你喜欢
      • 2011-03-28
      • 1970-01-01
      • 2013-03-19
      • 2012-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多