【问题标题】:Writing Oracle stored procedure with Oracle table as Input parameter使用 Oracle 表作为输入参数编写 Oracle 存储过程
【发布时间】:2020-09-30 14:20:21
【问题描述】:

如何编写以表(X)为输入参数的Oracle存储过程,并在过程中使用表X与另一个表Y连接?

表 X 将有数千条记录。

不希望将表名作为 varchar 传递,然后使用动态 SQL(因此,此选项不适用)

【问题讨论】:

  • 您的最终结果应该如何相似?
  • 如何在不知道需要加入哪一列的情况下加入另一个表?
  • 你可以假设任何列,假设 ID,加入。我知道要加入的专栏。只是我无法在过程的连接查询中使用输入表。
  • 你的oracle版本是什么?是 18 岁以上吗?
  • @VikashKumarSharma "不希望将表名作为 varchar 传递" 那么你想如何声明你的输入参数?向我们展示想要的过程声明

标签: oracle plsql


【解决方案1】:

从 19.6 开始,您可以创建 SQL 宏。这将返回一个带有您的查询片段的字符串。

在解析时,数据库将使用您传递给它的表查找/替换表参数:

create or replace function f ( tab dbms_tf.table_t ) 
  return varchar2 sql_macro as
begin
  return 'select * from tab 
    join ( select level rn from dual connect by level <= 2 ) 
    on c1 = rn';
end f;
/

create table t1 (
  c1 int
);
create table t2 (
  c1 int
);

insert into t1 values ( 1 );
insert into t2 values ( 2 );


select * from f ( t1 );

C1       RN   
    1     1 

select * from f ( t2 );

C1       RN   
    2     2 

【讨论】:

    【解决方案2】:

    您可能会发现另一种有趣的方法:将游标变量传递给流水线表函数,在 SQL 中调用它,允许您按字面意思传递表的内容(select * from...),批量收集到集合中,然后加入与您的另一张桌子合集!

    DROP TYPE tickertype FORCE;
    DROP TYPE tickertypeset FORCE;
    DROP TABLE stocktable;
    DROP TABLE tickertable;
    
    CREATE TABLE stocktable
    (
       ticker        VARCHAR2 (20),
       trade_date    DATE,
       open_price    NUMBER,
       close_price   NUMBER
    )
    /
    
    BEGIN
       FOR indx IN 1 .. 100
       LOOP
          INSERT INTO stocktable
               VALUES ('STK' || indx,
                       SYSDATE,
                       indx,
                       indx + 15);
       END LOOP;
    
       COMMIT;
    END;
    /
    
    CREATE TABLE tickertable
    (
       ticker      VARCHAR2 (20),
       pricedate   DATE,
       pricetype   VARCHAR2 (1),
       price       NUMBER
    )
    /
    
    CREATE TYPE tickertype AS OBJECT
    (
       ticker VARCHAR2 (20),
       pricedate DATE,
       pricetype VARCHAR2 (1),
       price NUMBER
    );
    /
    
    BEGIN
       FOR indx IN 1 .. 100
       LOOP
          INSERT INTO tickertable
               VALUES ('STK' || indx,
                       SYSDATE,
                       'O',
                       indx);
       END LOOP;
    
       COMMIT;
    END;
    /
    
    CREATE TYPE tickertypeset AS TABLE OF tickertype;
    /
    
    CREATE OR REPLACE PACKAGE refcur_pkg
       AUTHID DEFINER
    IS
       TYPE refcur_t IS REF CURSOR
          RETURN stocktable%ROWTYPE;
    
       TYPE dataset_tt IS TABLE OF stocktable%ROWTYPE;
    END refcur_pkg;
    /
    
    CREATE OR REPLACE FUNCTION pipeliner (dataset refcur_pkg.refcur_t)
       RETURN tickertypeset
       PIPELINED
       AUTHID DEFINER
    IS
       l_row_as_object   tickertype
                            := tickertype (NULL,
                                           NULL,
                                           NULL,
                                           NULL);
    
       l_dataset         refcur_pkg.dataset_tt;
       l_count             PLS_INTEGER;
    BEGIN
       FETCH dataset BULK COLLECT INTO l_dataset;
    
       CLOSE dataset;
    
       /* Let's do a join with another table. */
       SELECT COUNT (*) into l_count
         FROM TABLE (l_dataset) st, tickertable tt
        WHERE st.ticker = tt.ticker;
    
       DBMS_OUTPUT.put_line ('Count = ' ||l_count);
    
       l_row_as_object.ticker := 'ABC';
       PIPE ROW (l_row_as_object);
    
       RETURN;
    END;
    /
    
    BEGIN
       FOR rec
          IN (SELECT * FROM TABLE (pipeliner (CURSOR (SELECT * FROM stocktable))))
       LOOP
          DBMS_OUTPUT.put_line (rec.ticker);
       END LOOP;
    END;
    /
    

    我看到了这个输出:

    Count = 100
    ABC
    

    【讨论】:

      【解决方案3】:

      在 SQL 范围内创建表类型:

      CREATE TYPE string_list AS TABLE OF VARCHAR2(5);
      

      然后将其用作存储过程的参数,并使用表集合表达式将其连接到另一个表:

      CREATE PROCEDURE test_proc(
        p_list IN string_list
      )
      IS
        v_cursor SYS_REFCURSOR;
        v_string VARCHAR2(10);
      BEGIN
        OPEN v_cursor FOR
        SELECT d.*
        FROM   DUAL d
               INNER JOIN TABLE( p_list ) t
               ON ( d.DUMMY = t.COLUMN_VALUE );
      
        -- do something with the cursor.
       LOOP 
         FETCH v_cursor into v_string;
         EXIT WHEN v_cursor%NOTFOUND;
         DBMS_OUTPUT.PUT_LINE( v_string );
       END LOOP;
      END;
      /
      

      那么你就可以调用它了:

      BEGIN
        test_proc( string_list( 'X', 'Y', 'Z' ) ) ;
      END;
      /
      

      它输出:

      X
      

      db小提琴here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 1970-01-01
        • 1970-01-01
        • 2015-12-09
        • 1970-01-01
        相关资源
        最近更新 更多