在Oracle上实现表值函数

eanckbw9  于 2023-05-06  发布在  Oracle
关注(0)|答案(2)|浏览(283)

我习惯了SQL Server,所以Oracle对我来说是新的。我需要在Oracle中执行一个表值函数,我从不同的站点拼凑了以下代码。我需要传入一个参数。前两个create语句似乎运行良好,没有错误。但是,Create函数会出现以下错误:
PLS-00306:调用“TBL_CREATININES”时参数的数量或类型错误
下面是完整的代码:

CREATE OR REPLACE TYPE tbl_lab_row AS OBJECT (
 EVENT_END_DT_TM DATE, 
 RESULT_VAL VARCHAR2(255 CHAR), 
 RESULT_UNITS_CD NUMBER, 
 EVENT_CD NUMBER
);

CREATE OR REPLACE TYPE tbl_creatinines AS TABLE OF tbl_lab_row;

CREATE OR REPLACE FUNCTION tvf_creatinine_for_enc(p_enc_id NUMBER)
RETURN tbl_creatinines PIPELINED
IS
BEGIN
  FOR r IN (SELECT EVENT_END_DT_TM, RESULT_VAL, RESULT_UNITS_CD, EVENT_CD
            FROM SCHEMA.TABLE
            WHERE ENCNTR_ID = p_enc_id AND EVENT_CD IN(...listed codes here removed for brevity
    ))
  LOOP
    PIPE ROW (tbl_creatinines(r.EVENT_END_DT_TM, r.RESULT_VAL, r.RESULT_UNITS_CD, r.EVENT_CD));
  END LOOP;
  RETURN;
END;

任何帮助都非常感谢。

ru9i0ody

ru9i0ody1#

管道表函数需要管道 singular 对象类型,然后将自动转换为 nested 表类型。我修改了下面的函数以使其正确工作,尽管我使用了DUAL和硬编码值以避免创建表。

CREATE OR REPLACE FUNCTION tvf_creatinine_for_enc(p_enc_id NUMBER)
RETURN tbl_creatinines PIPELINED
IS
BEGIN
  FOR r IN (SELECT sysdate EVENT_END_DT_TM, 'A' RESULT_VAL, 1 RESULT_UNITS_CD, 2 EVENT_CD
            FROM DUAL
            WHERE 1 = p_enc_id
    )
  LOOP
    PIPE ROW (tbl_lab_row(r.EVENT_END_DT_TM, r.RESULT_VAL, r.RESULT_UNITS_CD, r.EVENT_CD));
  END LOOP;
  RETURN;
END;
/

select * from table(tvf_creatinine_for_enc(1));

但并非所有表函数都是流水线的。构建一个只返回嵌套变量的函数通常更容易,也可能更快。这种方法的缺点是,一个大的嵌套表变量可能会消耗大量内存。不要使用这种方法返回大量数据。

CREATE OR REPLACE FUNCTION tvf_creatinine_for_enc2(p_enc_id NUMBER)
RETURN tbl_creatinines
IS
  v_rows tbl_creatinines;
BEGIN
  SELECT tbl_lab_row(EVENT_END_DT_TM => sysdate, RESULT_VAL => 'A', RESULT_UNITS_CD => 1 , EVENT_CD => 2)
  BULK COLLECT INTO v_rows  
  FROM DUAL
  WHERE 1 = p_enc_id;

  RETURN v_rows;
END;
/

select * from table(tvf_creatinine_for_enc2(1));
2jcobegt

2jcobegt2#

如果你需要将参数“推送”到SQL代码深处,而通过where条件推送的一般 predicate 没有访问权限(类似于参数化视图),你可以使用SQL宏(自19.7起可用)作为管道函数的替代方案。
好处是SQL宏返回与其他SQL代码合并的SQL代码,并且您不需要创建新类型。缺点是你不能在内部执行逐行处理(只要它返回一部分SQL代码),但其中一些可以使用可用的SQL结构来执行,如递归CTE,内联函数声明(with function <funcname> ...),match_recognizemodel,横向连接等。

create function f_get_dates(
  p_from date,
  p_to date,
  p_interval interval day to second default interval '1' day
)
return varchar2 sql_macro(table)
as
begin
  return q'{
  select
    trunc(f_get_dates.p_from) + (level - 1) * f_get_dates.p_interval as date_from
    , trunc(f_get_dates.p_from) + level * f_get_dates.p_interval as date_to
    , level as rn
  from dual
  connect by
    trunc(f_get_dates.p_from) + level * f_get_dates.p_interval <= trunc(f_get_dates.p_to)
  }';
end;/
select *
from f_get_dates(sysdate, sysdate + 4)
日期_自日期至RN
2023-05-05- 012023-05-06 2023-05-061
2023-05-06 2023-05-062023-05-07 2023-05-07
2023-05-07 2023-05-072023-05-08 2023-05-08
2023-05-08 2023-05-082023-05-09 2023-05-09四个

fiddle

相关问题