【问题标题】:Reuse Select Statement within a Procedure在过程中重用 Select 语句
【发布时间】:2020-09-09 09:25:49
【问题描述】:

我喜欢做类似的事情

create tmp_table as ( select 1 some_value, 2 some_other_value from dual union select 3 some_value, 4 some_other_value from dual );

insert into table1 (field1) select some_value from tmp_table;

update table2 set field2 = 5 where field1 in ( select some_value from tmp_table );

drop tmp_table;

有没有更好的方法呢?也许是 WITH 语句的迭代使用?

with tmp_statement as (select ...) ( insert... update ... )

编辑:

您好,很抱歉这个非常笼统的问题。基本上,我想通过拆分操作来改进一些公司语法(选择..循环...在这里慢慢地逐行执行),但保持“仅选择一个”规则有效,因为选择将是广泛的,而您无论如何只想编辑一个选择。我尝试使用 with,因为它似乎更接近现有语法。但也许将选择加载到临时/私有/实际表中的功能只是更好的方法。

谢谢大家!

【问题讨论】:

  • 保留临时表以供重用如何? 19c 中有私有临时表,但它们在 PL/SQL 中并不能真正帮助您,因为它需要在编译时定义表。或者,收集可能会有所帮助。
  • 尝试更好地解释您想要实现的目标。插入和更新可以组合在一个目标表相同的合并语句中。在你的情况下,这是不可能的,因为你想插入和更新两个不同的表。

标签: sql oracle with-statement


【解决方案1】:

如果您正在寻找一个纯 SQL 解决方案来跨多个语句引用一个值,请使用替换变量(适用于 SQL*Plus、SQL Developer、sqlcl 和任何其他支持 SQL*Plus 命令的环境):

ACCEPT some_value PROMPT "Please enter a value for SOME_VALUE:"

insert into table1 (field1) select '&&some_value' from dual;

update table2 set field2 = 5 where field1 in ('&&some_value' );

但是,您对基于集合的操作的使用表明您期望 TMP_TABLE 可能包含不止一行。在这种情况下,上述方法不起作用。如果是这种情况,请编辑您的问题以提供有关您要达到的目标的更多详细信息。

对此有多种解决方案,包括 PL/SQL 集合或跨执行保留 TMP_TABLE。这取决于您希望多久执行一次此操作。

创建和删除 TMP_TABLE 等对象的反模式在具有 T-SQL 背景的开发人员中很常见。 Oracle 在几个方面与 SQL Server 不同,这是其中之一:它不赞成动态执行 DDL,作为某些事务逻辑的一部分。

您可能需要的方法是将 TMP_TABLE 创建为 GLOBAL TEMPORARY TABLE。这是一个永久数据结构,但它的数据在事务(或会话)结束时被丢弃。如果您选择这种方法,您将创建一次 TMP_TABLE,然后在需要时使用它,而不会在每个会话结束时删除。 Find out more.

【讨论】:

    【解决方案2】:

    如果您使用的是 Oracle 18c 或更高版本,则可以使用新的private temporary tables

    在您的具体情况下,您可以创建私有表,然后进行插入和更新、提交和退出。私有临时表可以是特定于事务或特定于会话的。

    考虑参数 PRIVATE_TEMP_TABLE_PREFIX 的值,它决定了命名约定的前缀

    create private temporary table ora$ptt_tmp_table on commit drop definition 
    as select 1 as some_value from dual  ;          
    
    insert into table1 (field1) select some_value from ora$ptt_tmp_table  ;
    
    update table2 set field2 = 5 where field1 in ( select some_value from  ora$ptt_tmp_table  );
    
    commit ; -- here the private table is dropped automatically
    

    【讨论】:

    • 不错的 PTT 演示,但 OP 说“在一个程序内”,这让事情有点复杂。
    【解决方案3】:

    您没有发布足够的详细信息,所以我将尝试列出所有变体:

    1. 如果您只需要几个变量,那么您有以下选择:

      • 替换变量 (&var)
      • PL/SQL 变量,可用的不同范围,例如,局部变量、私有或公共包变量,甚至对象
      • 集合:嵌套表或可变数组,例如:
        • varray:select * from table(sys.odcivarchar2list('a','b','c'));
        • 嵌套表:select * from table(sys.ku$_vcnt('a','b','c'));
        • numpairs 嵌套表:
    select * 
    from
     table(
       sys.ku$_objnumpairlist(
             ku$_objnumpair(1,2),
             ku$_objnumpair(3,4)));
          NUM1       NUM2
    ---------- ----------
             1          2
             3          4
    
    • 上下文变量,例如:
    SQL> call DBMS_SESSION.SET_CONTEXT('CLIENTCONTEXT', 'var1', 'value1');
    
    Call completed.
    
    SQL> select SYS_CONTEXT('CLIENTCONTEXT', 'var1') as var1 from dual;
    
    VAR1
    -----------------
    value1
    
    1. 如果需要存储数据集(行集):
    • 全局临时表(甚至私有临时表 (18c+))
    • 收藏

    【讨论】:

      猜你喜欢
      • 2016-01-06
      • 1970-01-01
      • 2011-08-27
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多