PL / SQL的隐藏功能

时间:2009-06-23 09:20:04

标签: sql oracle plsql

根据"Hidden features of..."系列问题,PL / SQL的一些鲜为人知的功能对您有用吗?

编辑:特定于PL / SQL的功能优于Oracle SQL语法的功能。但是,因为PL / SQL可以使用大多数Oracle的SQL结构,所以如果它们在PL / SQL中编程更容易,就可以包含它们。

12 个答案:

答案 0 :(得分:25)

您可以覆盖变量,可以命名匿名块,您仍然可以按名称引用重写的变量:

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;

答案 1 :(得分:17)

除了整数之外,您还可以通过其他类型索引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;

答案 2 :(得分:15)

真正隐藏的oracle函数是OVERLAPS函数,但使用任何不支持的功能可能不是很明智。

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

答案 3 :(得分:13)

我已经取得巨大成功的一个鲜为人知的功能是能够使用声明为%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;

虽然它咀嚼了更多的重做表空间,但它确实使得插入数据(尤其是更大的表格)更加清晰。它还避免了存储要插入的每个列的值所需的众多变量。

答案 4 :(得分:12)

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

DECLARE

    PROCEDURE print(text VARCHAR2) IS
    BEGIN
        DBMS_OUTPUT.put_line(text);
    END;

BEGIN

    print('Yay!');
    print('Woo hoo!');

END;

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

答案 5 :(得分:12)

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

SELECT *
  FROM MASSIVE_TABLE SAMPLE (5);

前一个语句检索由大量表中存储的最多5%记录组成的随机集,名为MASSIVE_TABLE。

答案 6 :(得分:10)

可能没有足够的隐藏,但我喜欢允许make upserts(插入或更新)的 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>];

答案 7 :(得分:10)

我对Hidden Features in Oracle的回答与此相关:

由于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.

答案 8 :(得分:7)

我使用了很多PL / SQL程序构造(Steven Feuerstein和Chen Shapira)。用于chaching的关联数组,但它不预加载所有数据,但如果需要则从数据库获取数据并将其放入关联数组中。

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

答案 9 :(得分:6)

  1. 未记录的函数:dbms_system.ksdwrt(写入警报/跟踪文件)
  2. DBMS_SQL包(作为其使用示例,请参阅this question
  3. AUTHID CURRENT_USER条款
  4. Conditional compilation

答案 10 :(得分:4)

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

答案 11 :(得分:3)

您可以通过向循环添加标签然后GOTO此标签来模拟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;