0

我有一个函数,它接受主键并用逗号分隔它们。

甲骨文功能:

create or replace function split(
  list in CHAR,
  delimiter in CHAR default ','
) 

return split_tbl as
  splitted split_tbl := split_tbl();
  i pls_integer := 0;
  list_ varchar2(32767) := list;

begin
  loop
    i := instr(list_, delimiter);
    if i > 0 then
      splitted.extend(1);
      splitted(splitted.last) := substr(list_, 1, i - 1);
      list_ := substr(list_, i + length(delimiter));
    else
      splitted.extend(1);
      splitted(splitted.last) := list_;
      return splitted;
    end if;
  end loop;
end;

我在 SQL Server 中有这个查询,它在函数表中返回这个查询的数据

select maxUserSalary.id as 'UserSalary'
into #usersalary
from dbo.Split(@usersalary,';') as userid
cross apply (
    select top 1 * from User_Salaryas usersalary
    where usersalary.User_Id= userid.item
    order by usersalary.Date desc
)  as maxUserSalary

问题是,我无法cross apply在 Oracle 中使用将这些数据放入返回表的函数中。

如何使用cross applyOracle 在函数中返回这些数据?

4

2 回答 2

2

您使用的是 Oracle 18c,因此您可以使用 CROSS APPLY 语法。Oracle 在 12c 中添加了它(以及 LATERAL 和 OUTER APPLY )。

这是您的逻辑的简化版本:

select us.name
       , us.salary
from table(split('FOX IN SOCKS,THING ONE,THING TWO')) t       
     cross apply (select us.name, max(us.salary) as salary 
                  from user_salaries us
                  where us.name = t.column_value ) us

db<>fiddle 上有一个工作演示


如果这不能完全解决您的问题,请发布一个完整的问题,其中包含表结构、示例数据和从该示例派生的预期输出。

于 2020-01-06T18:31:05.220 回答
0

我认为 APC 很好地回答了您的直接问题。作为旁注,我想建议不要编写自己的函数来执行此操作。有几种现有的解决方案可以将分隔的字符串值拆分为虚拟表,这些虚拟表不需要您创建自己的自定义类型,也没有 SQL 和 PL/SQL 引擎之间的上下文切换的性能开销。

-- example data - remove this to test with your User_Salary table
with User_Salary as (select 1 as id, 'A' as user_id, sysdate as "Date" from dual 
                     union select 2, 'B', sysdate from dual)
-- your query:
select maxUserSalary.id as "UserSalary"
from (select trim(COLUMN_VALUE) as item 
      from xmltable(('"'||replace(:usersalary, ';', '","')||'"'))) userid -- note ';' delimiter
cross apply (
    select * from User_Salary usersalary
    where usersalary.User_Id = userid.item
    order by usersalary."Date" desc
    fetch first 1 row only
) maxUserSalary;

如果你运行它并传入'A;B;C'for :usersalary,你会得到12返回。

几点注意事项:

  • 在此示例中,我将;其用作分隔符,因为这是您的查询使用的。
  • 我试图匹配您的表/列名,但您的列名Date无效 - 它是 Oracle 保留关键字,因此必须将其放在引号中才能成为有效的列名。
  • 作为列标识符,"UserSalary"也应该有双引号,而不是单引号。
  • 您不能as在表别名中使用。
  • 我删除了into usersalary,因为into仅用于返回单行的查询,并且您的查询可以返回多行。
于 2020-01-06T19:05:31.990 回答