SQL Сервер до Oracle - с помощью Cross Apply с Oracle - PullRequest
0 голосов
/ 06 января 2020

У меня есть функция, которая берет первичные ключи и разделяет их запятыми.

Oracle function:

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 Сервер, который возвращает данные этого запроса в таблице функций

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 apply с Oracle, чтобы вернуть эти данные в функцию?

Ответы [ 2 ]

2 голосов
/ 06 января 2020

Вы используете Oracle 18 c, поэтому вы можете использовать синтаксис CROSS APPLY. Oracle добавил его (а также LATERAL и OUTER APPLY) в 12 c.

Вот упрощенная версия вашей логики c:

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 .


Если это не решит полностью вашу проблему, пожалуйста, опубликуйте полный вопрос со структурами таблиц, примерами данных и ожидаемым результатом, полученным из этого образца .

0 голосов
/ 06 января 2020

Я думаю, что AP C хорошо ответил на ваш прямой вопрос. Как примечание, я хотел бы предложить НЕ писать свою собственную функцию, чтобы сделать это вообще. Существует несколько существующих решений для разделения строковых значений с разделителями на виртуальные таблицы, которые не требуют создания собственных пользовательских типов и не влияют на производительность переключения контекста между 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' для :usersalary, вы получите 1 и 2 назад.

A несколько замечаний:

  • В этом примере я использую ; в качестве разделителя, поскольку именно этот запрос используется.
  • Я пытался сопоставить имена вашей таблицы / столбца, но имя вашего столбца Date недопустимо - это зарезервированное ключевое слово * 1034, поэтому оно должно быть заключено в кавычки, чтобы быть действительным именем столбца.
  • Как идентификатор столбца, "UserSalary" также должен иметь двойные кавычки, а не одинарные.
  • Нельзя использовать as в псевдонимах таблиц.
  • Я удалил into usersalary, поскольку into используется только с запросами, которые возвращают одну строку, и ваш запрос может возвращать несколько строк.
...