Oracle - Return 通过没有显式对象的 SELECtable 函数的结果集/table 类型
Oracle - Return a result set via a SELECTable function without explicit object / table types
我正在尝试找到一种简单且易于维护的方法来 return 通过可以在 SELECT
语句中引用的函数来生成结果集,如下所示:
SELECT u.UserId, u.UserName, up.ProfileName
FROM GetUser(1) u
INNER JOIN user_profile up ON u.user_id = up.user_id;
这是我在 Postgres 中的内容:
CREATE OR REPLACE FUNCTION GetUser(
pUserId INTEGER
)
RETURNS TABLE (UserId INTEGER, UserClass CHAR(2), UserName VARCHAR(100)) AS $$
BEGIN
RETURN QUERY
SELECT UserId, UserClass, UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)
;
END;
$$ LANGUAGE 'plpgsql';
SELECT * FROM GetUser(1);
这是我在 Oracle 中所处位置的示例:
CREATE OR REPLACE TYPE appuser AS OBJECT (UserName VARCHAR(255)); -- user type
CREATE OR REPLACE TYPE appuser_table AS TABLE OF appuser; -- user table type
CREATE OR REPLACE FUNCTION GetUser (
pUserId IN VARCHAR2 DEFAULT NULL
) RETURN appuser_table PIPELINED AS
BEGIN
FOR v_Rec IN (
SELECT UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)
)
LOOP
PIPE ROW (appuser(v_Rec.UserName));
END LOOP;
RETURN;
END;
SELECT * FROM TABLE(GetUser(NULL));
可以用,但是很麻烦,需要多个DDL。在 Postgres 中,我可以在函数中轻松完成所有这些操作:
RETURNS TABLE (ObjectId INTEGER, ObjectClass CHAR(2), ObjectName VARCHAR(100))
在 Oracle 中是否有更简洁的方法来执行此操作?
相关帖子
Pipelined Functions
基本上,按照您的说法,您需要创建的只是一个函数——使用 Oracle 的内置类型。这是一个基于 Scott 的 EMP
table 的示例(因为我没有你的):
SQL> select deptno, ename from emp where deptno = 10;
DEPTNO ENAME
---------- ----------
10 CLARK
10 KING
10 MILLER
函数:
SQL> create or replace function getuser (puserid in number default null)
2 return sys.odcivarchar2list
3 is
4 retval sys.odcivarchar2list;
5 begin
6 select ename
7 bulk collect into retval
8 from emp
9 where deptno = puserid or puserid is null;
10
11 return retval;
12 end;
13 /
Function created.
测试:
SQL> select * From table(getuser(10));
COLUMN_VALUE
----------------------------------------------------------------------------
CLARK
KING
MILLER
SQL>
如果您想获得“更智能”的列名而不是 COLUMN_VALUE
,那么您必须创建自己的类型。像这样:
SQL> create or replace type t_tf_row as object (ename varchar2(20));
2 /
Type created.
SQL> create or replace type t_tf_tab is table of t_tf_row;
2 /
Type created.
SQL> create or replace function getuser (puserid in number default null)
2 return t_tf_tab
3 is
4 retval t_tf_tab;
5 begin
6 select t_tf_row(ename)
7 bulk collect into retval
8 from emp
9 where deptno = puserid or puserid is null;
10 return retval;
11 end;
12 /
Function created.
SQL> select * from table(getuser(10));
ENAME
--------------------
CLARK
KING
MILLER
SQL>
具有定义的 table 类型(作为 SQL 类型或在 PL/SQL 包中)的流水线函数是在 19.6 之前实现此目的的唯一方法。使用此版本后,您可以使用 SQL Macros 。对于您的特殊要求,您可以直接替换,例如:
create or replace function getUser (pUserId integer)
return varchar2 sql_macro
is
begin
return q'{SELECT UserId, UserClass, UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)}';
end getUser;
/
或者您可以使优化器更轻松地将查询分为两种可能的形式 - return 所有内容或 return 仅匹配 pUserId
值的行:
create or replace function getUser (pUserId integer)
return varchar2 sql_macro
is
begin
if pUserId is null then
return q'{SELECT UserId, UserClass, UserName FROM Users}';
else
return q'{SELECT UserId, UserClass, UserName FROM Users WHERE UserId = pUserId}';
end if;
end getUser;
/
我整理了一份 demo on LiveSQL。
我正在尝试找到一种简单且易于维护的方法来 return 通过可以在 SELECT
语句中引用的函数来生成结果集,如下所示:
SELECT u.UserId, u.UserName, up.ProfileName
FROM GetUser(1) u
INNER JOIN user_profile up ON u.user_id = up.user_id;
这是我在 Postgres 中的内容:
CREATE OR REPLACE FUNCTION GetUser(
pUserId INTEGER
)
RETURNS TABLE (UserId INTEGER, UserClass CHAR(2), UserName VARCHAR(100)) AS $$
BEGIN
RETURN QUERY
SELECT UserId, UserClass, UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)
;
END;
$$ LANGUAGE 'plpgsql';
SELECT * FROM GetUser(1);
这是我在 Oracle 中所处位置的示例:
CREATE OR REPLACE TYPE appuser AS OBJECT (UserName VARCHAR(255)); -- user type
CREATE OR REPLACE TYPE appuser_table AS TABLE OF appuser; -- user table type
CREATE OR REPLACE FUNCTION GetUser (
pUserId IN VARCHAR2 DEFAULT NULL
) RETURN appuser_table PIPELINED AS
BEGIN
FOR v_Rec IN (
SELECT UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)
)
LOOP
PIPE ROW (appuser(v_Rec.UserName));
END LOOP;
RETURN;
END;
SELECT * FROM TABLE(GetUser(NULL));
可以用,但是很麻烦,需要多个DDL。在 Postgres 中,我可以在函数中轻松完成所有这些操作:
RETURNS TABLE (ObjectId INTEGER, ObjectClass CHAR(2), ObjectName VARCHAR(100))
在 Oracle 中是否有更简洁的方法来执行此操作?
相关帖子
Pipelined Functions
基本上,按照您的说法,您需要创建的只是一个函数——使用 Oracle 的内置类型。这是一个基于 Scott 的 EMP
table 的示例(因为我没有你的):
SQL> select deptno, ename from emp where deptno = 10;
DEPTNO ENAME
---------- ----------
10 CLARK
10 KING
10 MILLER
函数:
SQL> create or replace function getuser (puserid in number default null)
2 return sys.odcivarchar2list
3 is
4 retval sys.odcivarchar2list;
5 begin
6 select ename
7 bulk collect into retval
8 from emp
9 where deptno = puserid or puserid is null;
10
11 return retval;
12 end;
13 /
Function created.
测试:
SQL> select * From table(getuser(10));
COLUMN_VALUE
----------------------------------------------------------------------------
CLARK
KING
MILLER
SQL>
如果您想获得“更智能”的列名而不是 COLUMN_VALUE
,那么您必须创建自己的类型。像这样:
SQL> create or replace type t_tf_row as object (ename varchar2(20));
2 /
Type created.
SQL> create or replace type t_tf_tab is table of t_tf_row;
2 /
Type created.
SQL> create or replace function getuser (puserid in number default null)
2 return t_tf_tab
3 is
4 retval t_tf_tab;
5 begin
6 select t_tf_row(ename)
7 bulk collect into retval
8 from emp
9 where deptno = puserid or puserid is null;
10 return retval;
11 end;
12 /
Function created.
SQL> select * from table(getuser(10));
ENAME
--------------------
CLARK
KING
MILLER
SQL>
具有定义的 table 类型(作为 SQL 类型或在 PL/SQL 包中)的流水线函数是在 19.6 之前实现此目的的唯一方法。使用此版本后,您可以使用 SQL Macros 。对于您的特殊要求,您可以直接替换,例如:
create or replace function getUser (pUserId integer)
return varchar2 sql_macro
is
begin
return q'{SELECT UserId, UserClass, UserName
FROM Users
WHERE (UserId = pUserId OR pUserId IS NULL)}';
end getUser;
/
或者您可以使优化器更轻松地将查询分为两种可能的形式 - return 所有内容或 return 仅匹配 pUserId
值的行:
create or replace function getUser (pUserId integer)
return varchar2 sql_macro
is
begin
if pUserId is null then
return q'{SELECT UserId, UserClass, UserName FROM Users}';
else
return q'{SELECT UserId, UserClass, UserName FROM Users WHERE UserId = pUserId}';
end if;
end getUser;
/
我整理了一份 demo on LiveSQL。