【问题标题】:Hidden features of PL/SQL [closed]PL/SQL 的隐藏特性 [关闭]
【发布时间】:2010-11-05 02:43:01
【问题描述】:

鉴于"Hidden features of..." 系列问题,PL/SQL 的哪些鲜为人知的特性对您有用?

编辑: PL/SQL 特有的特性优于 Oracle 的 SQL 语法特性。但是,由于 PL/SQL 可以使用 Oracle 的大部分 SQL 结构,如果它们使 PL/SQL 编程更容易,它们可能会被包含在内。

【问题讨论】:

  • 你包括SQL吗?这本身就是一个“完全不同的话题”。
  • 我更喜欢 PL/SQL 过程结构。然而,只能在 Oracle 中找到的 SQL 结构也有一定的资格,因为它们可以从 PL/SQL 块中调用。

标签: sql oracle plsql


【解决方案1】:

真正隐藏的预言机功能是 OVERLAPS 功能,但使用任何不受支持的功能可能不是很明智。

select 'yes' from dual where (sysdate-5,sysdate) overlaps (sysdate-2,sysdate-1);

【讨论】:

  • 遗憾的是它没有记录。它是如此清晰和简洁!
  • 不知能否直接在PL/SQL IF语句中使用...
  • Paynter: 是 - 如果 (sysdate-5,sysdate) 与 (sysdate-2,sysdate-1) 重叠则开始 dbms_output.put_line('yes');万一;结束;
  • 虽然写起来并不太痛苦:select 'yes' from dual where sysdate-2 BETWEEN sysdate-5 AND sysdate OR sysdate-1 BETWEEN sysdate-5 AND sysdate;
  • overlaps() 看起来正是我需要的!虽然它不受支持让我想知道我是否应该使用它。
【解决方案2】:

您可以通过向循环添加标签然后转到此标签来模拟 CONTINUE:

declare
   i integer;
begin
   i := 0;

   <<My_Small_Loop>>loop

      i := i + 1;
      if i <= 3 then goto My_Small_Loop; -- => means continue
      end if;

      exit;

   end loop;
end;

【讨论】:

    【解决方案3】:

    您知道使用 SAMPLE (K) 选项只能选择由最多 K% 的 Oracle 表组成的样本吗?

    SELECT *
      FROM MASSIVE_TABLE SAMPLE (5);
    

    前面的语句检索由存储在名为 MASSIVE_TABLE 的海量表中最多 5% 的记录组成的随机集合。

    【讨论】:

    • 这不是 PL/SQL。
    【解决方案4】:

    过程和函数可以在DECLARE 块中定义:

    DECLARE
    
        PROCEDURE print(text VARCHAR2) IS
        BEGIN
            DBMS_OUTPUT.put_line(text);
        END;
    
    BEGIN
    
        print('Yay!');
        print('Woo hoo!');
    
    END;
    

    这对于创建独立脚本很方便。

    【讨论】:

    • 您还可以嵌套过程和函数,这在您需要将大过程分解为几个较小的过程而不传递大量参数时特别有用。
    【解决方案5】:

    我对@9​​87654321@ 的回答与此处相关:

    由于 Apex 现在是每个 Oracle 数据库的一部分,即使您不使用 Apex,这些 Apex 实用程序功能也很有用:

    SQL> declare
      2    v_array apex_application_global.vc_arr2;
      3    v_string varchar2(2000);
      4  begin
      5  
      6    -- Convert delimited string to array
      7    v_array := apex_util.string_to_table('alpha,beta,gamma,delta', ',');
      8    for i in 1..v_array.count
      9    loop
     10      dbms_output.put_line(v_array(i));
     11    end loop;
     12  
     13    -- Convert array to delimited string
     14    v_string := apex_util.table_to_string(v_array,'|');
     15    dbms_output.put_line(v_string);
     16  end;
     17  /
    alpha
    beta
    gamma
    delta
    alpha|beta|gamma|delta
    
    PL/SQL procedure successfully completed.
    

    【讨论】:

    • nope.. apex isnt 'standard'.. on Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - 生产“desc apex_util”给出错误: ORA-04043: 对象 apex_util 不存在
    • @ShoeLace,实际上我相信它至少从 10.2 开始就是标准的。但是 (a) 该包可能仍被称为 htmldb_util,并且 (b) 它可能需要 DBA 进行配置才能使其可用。恐怕我不知道这两个问题的确切答案。
    【解决方案6】:

    动态 PL/SQL 很丑,但可以做一些有趣的事情。例如,名称可以被视为变量,我之前用它来遍历像数组这样的 %rowtype 变量,并创建一个函数,对于给定的表名,该函数将返回一个游标,该游标选择具有默认值的单行每列的。两者都是非规范化表的有用解决方法。

    【讨论】:

      【解决方案7】:

      您可以按整数以外的其他类型索引 pl/sql 表。通过这种方式,您可以创建类似“字典”的结构,从而使您的代码更易于阅读:

      例子:

      DECLARE
        TYPE dictionary IS TABLE OF VARCHAR2(200) INDEX BY VARCHAR2(100);
        dict dictionary;
      BEGIN
        dict('NAME') := 'John Doe';
        dict('CITY') := 'New York';
      
        dbms_output.put_line('Name:' || dict('NAME'));
      END;
      

      【讨论】:

      • 再说一次,我不知道你能做到的另一件事!很有用!
      【解决方案8】:
      1. 未记录的函数:dbms_system.ksdwrt(写入警报/跟踪文件)
      2. DBMS_SQL 包(作为其使用示例,请参阅this question
      3. AUTHID CURRENT_USER 子句
      4. Conditional compilation

      【讨论】:

      • 小心使用dbms_system.ksdwrt()。使用它的程序可以作为 DoS 攻击的载体。
      • 隐藏特性:条件编译可以在 Oracle 9.2.0.6 中启用(它被向后移植以支持补丁版本)
      【解决方案9】:

      这是一个我经常使用的 PL/SQL 过程构造(感谢 Steven Feuerstein 和 Chen Shapira)。一个用于查询的关联数组,但它不会预先加载所有数据,而是根据需要从数据库中获取数据并将其放入关联数组中。

      create or replace
      PACKAGE justonce
      IS
        FUNCTION hair (code_in IN hairstyles.code%TYPE)
          RETURN hairstyles%ROWTYPE;
        TYPE hair_t IS TABLE OF hairstyles%ROWTYPE
          INDEX BY BINARY_INTEGER;
        hairs          hair_t;
      END justonce;
      
      create or replace 
      PACKAGE BODY justonce
      IS
        FUNCTION hair (code_in IN hairstyles.code%TYPE) RETURN hairstyles%ROWTYPE
        IS
          return_value   hairstyles%ROWTYPE;
          FUNCTION hair_from_database RETURN hairstyles%ROWTYPE
          IS
            CURSOR hair_cur IS
            SELECT * FROM hairstyles WHERE code = code_in;
          BEGIN
            OPEN hair_cur;
            FETCH hair_cur INTO return_value;
            CLOSE hair_cur;
            RETURN return_value;
          END hair_from_database;
        BEGIN
          IF NOT (hairs.exists(code_in))
          THEN
            dbms_output.put_line('Get record from database');
            hairs (code_in) := hair_from_database;
          END IF;
          RETURN hairs (code_in);
        END hair;
      END justonce;
      

      测试一下:

      declare
          h hairstyles%ROWTYPE;
      begin
         for i in 1000..1004
         loop
            h := justonce.hair(i);
            dbms_output.put_line(h.description);
         end loop;
         for i in 1000..1004
         loop
            h := justonce.hair(i);
            dbms_output.put_line(h.description||' '||h.price);
         end loop;
      
      end;
      /
      
      Get record from database
      CREWCUT
      Get record from database
      BOB
      Get record from database
      SHAG
      Get record from database
      BOUFFANT
      Get record from database
      PAGEBOY
      CREWCUT 10
      BOB 20
      SHAG 21
      BOUFFANT 11
      PAGEBOY 44
      

      【讨论】:

      • 那些表类型非常有用!我喜欢能够使用任意索引(在你的情况下,头发代码)来引用它的行。比传统数组好很多!
      【解决方案10】:

      你可以覆盖变量,你可以命名匿名块,你仍然可以通过名字来引用被覆盖的变量:

      PROCEDURE myproc IS
         n NUMBER;
      BEGIN
         n := 1;
         <<anon>>
         DECLARE
            n NUMBER;
         BEGIN
            n := 2;
            dbms_output.put_line('n=' || n);
            dbms_output.put_line('anon.n=' || anon.n);
            dbms_output.put_line('myproc.n=' || myproc.n);
         END anon;
      END myproc;
      

      【讨论】:

      • 我什至不知道块可以有标签!很有用!
      • 是的。许多人不知道我们可以标记循环。真的很好。
      • 不错。我不知道块标签
      【解决方案11】:

      可能还不够隐藏,但我喜欢 Merge 语句,它允许进行更新插入(插入或更新)

      MERGE <hint> INTO <table_name>
      USING <table_view_or_query>
      ON (<condition>)
      WHEN MATCHED THEN <update_clause>
      DELETE <where_clause>
      WHEN NOT MATCHED THEN <insert_clause>
      [LOG ERRORS <log_errors_clause> <reject limit <integer | unlimited>];
      

      【讨论】:

      • MERGE 不是 PL/SQL (3GL),而是 Oracle SQL 语句。
      • MERGE 是 SQL:2003 标准的一部分,可在大多数大型平台上使用。尽管如此,非常有用且未被充分利用。
      【解决方案12】:

      我取得了巨大成功的一个鲜为人知的功能是能够使用声明为%ROWTYPE 的变量插入表中。例如:

      CREATE TABLE CUSTOMERS (
          id NUMBER,
          name VARCHAR2(100),
          birth DATE,
          death DATE
      )
      
      PROCEDURE insert_customer IS
          customer CUSTOMERS%ROWTYPE;
      BEGIN
          customer.id := 45;
          customer.name := 'John Smith';
          customer.birth := TO_DATE('1978/04/03', 'YYYY/MM/DD');
      
          INSERT INTO CUSTOMERS VALUES customer;
      END;
      

      虽然它占用了更多的重做表空间,但它确实使插入数据(尤其是插入更大的表)更加清晰。它还避免了存储您希望插入的每一列的值所需的大量变量。

      【讨论】:

      • %ROWTYPE 节省了重复。
      猜你喜欢
      • 2010-09-05
      • 2010-10-12
      • 2010-10-20
      • 2010-10-17
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 2011-03-19
      • 1970-01-01
      相关资源
      最近更新 更多