使用 Oracle 表作为输入参数编写 Oracle 存储过程
Posted
技术标签:
【中文标题】使用 Oracle 表作为输入参数编写 Oracle 存储过程【英文标题】:Writing Oracle stored procedure with Oracle table as Input parameter 【发布时间】:2020-09-30 14:20:21 【问题描述】:如何编写以表(X)为输入参数的Oracle存储过程,并在过程中使用表X与另一个表Y连接?
表 X 将有数千条记录。
不希望将表名作为 varchar 传递,然后使用动态 SQL(因此,此选项不适用)
【问题讨论】:
您的最终结果应该如何相似? 如何在不知道需要加入哪一列的情况下加入另一个表? 你可以假设任何列,假设 ID,加入。我知道要加入的专栏。只是我无法在过程的连接查询中使用输入表。 你的oracle版本是什么?是 18 岁以上吗? @VikashKumarSharma "不希望将表名作为 varchar 传递" 那么你想如何声明你的输入参数?向我们展示想要的过程声明 【参考方案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
【讨论】:
以上是关于使用 Oracle 表作为输入参数编写 Oracle 存储过程的主要内容,如果未能解决你的问题,请参考以下文章