Конвертировать кусок SQL в функцию Oracle - PullRequest
0 голосов
/ 17 октября 2018

Моя таблица "COMMA_SEPERATED" выглядит примерно так

ID  NAME CITY
--- ---- -----------------------------
1   RAJ  CHENNAI, HYDERABAD, JABALPUR
2   SAM  BHOPAL,PUNE

Я хочу разделить каждый Город как новую запись, поэтому мой SQL: (работает нормально)

SELECT id, TRIM(CITY_NEW)
FROM COMMA_SEPERATED, xmltable
(
    'if (contains($X,",")) then ora:tokenize($X,"\,") else $X'
    passing city AS X
    columns CITY_NEW varchar2(4000) path '.'
);

Iхочу преобразовать этот кусок SQL в функцию, чтобы я мог просто вызвать такую ​​функцию

SELECT id, split_function(city) FROM COMMA_SEPERATED

Вывод:

1   CHENNAI
1   HYDERABAD
1   JABALPUR
2   BHOPAL
2   PUNE

Может кто-нибудь помочь с тем, как это сделать?Я очень плохо знаком с PL / SQL.

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Запрос, который вы пытаетесь получить:

SELECT id, split_function(city) FROM COMMA_SEPERATED

не будет работать, потому что вы пытаетесь вернуть несколько строк для каждой строки источника.Вы должны сделать это немного сложнее, к сожалению.

Если цель состоит в том, чтобы скрыть механизм расщепления, то самое близкое, о чем я могу подумать, - это создать функцию, которая возвращает коллекцию строк, которая может быть pipelined :

create or replace function split_function (p_string varchar2)
return sys.odcivarchar2list pipelined as
begin
  for r in (
    select result
    from xmltable (
      'if (contains($X,",")) then ora:tokenize($X,"\,") else $X'
      passing p_string as x
      columns result varchar2(4000) path '.'
    )
  )
  loop
    pipe row (trim(r.result));
  end loop;
end split_function;
/

Ваш предложенный вызов даст вам одну строку для каждого ID с коллекцией:

select id, split_function(city) from comma_seperated;

        ID SPLIT_FUNCTION(CITY)
---------- -----------------------------------------------------------------
         1 ODCIVARCHAR2LIST('CHENNAI', 'HYDERABAD', 'JABALPUR')
         2 ODCIVARCHAR2LIST('BHOPAL', 'PUNE')

, что не совсем то, что вы хотите;но вместо этого вы можете использовать выражение коллекции таблиц и перекрестное соединение для преобразования в несколько строк:

select cs.id, t.column_value as city
from comma_seperated cs
cross join table(split_function(cs.city)) t;

        ID CITY                          
---------- ------------------------------
         1 CHENNAI                       
         1 HYDERABAD                     
         1 JABALPUR                      
         2 BHOPAL                        
         2 PUNE                          

db <> fiddle demo .

Это не тактак просто, как вы надеялись, но, возможно, все же лучше, чем перекрестное соединение с xmltable(), особенно если вы хотите повторно использовать эту логику / функцию разделения в нескольких местах, а также скрыть детали того, как выполняется разделение -который позволит вам легко изменить механизм, если вы захотите, например, использовать более распространенное регулярное выражение для разделения.

0 голосов
/ 17 октября 2018

Помимо того, что показывал @Alex, вы также можете создать object и получить object, возвращенный через function.См. Ниже:

--Created an object to hold your result columns
create or replace type Obj IS OBJECT (id number, city varchar2(20));
/
--Table of object
create or replace type var_obj is table of Obj;

/
--Function with return as with Object type.
create or replace function splt_fnct
return var_obj
as
var var_obj:=var_obj();

begin
Select obj(col,col1)
bulk collect into var
from (
Select  distinct  col , regexp_substr(col1,'[^,]+',1,level) col1
from tbl
connect by regexp_substr(col1,'[^,]+',1,level) is not null
order by 1);

return var;
end;

/
--Selecting result   

 select *  from table(splt_fnct);

Редактировать: я пытался с решением @Alex и получил некоторую ошибку, как показано ниже:

create or replace function splt_fnct(input_strng varchar2)
return var_obj
as
var var_obj:=var_obj();

begin
Select obj(col,col1)
bulk collect into var
from (
select tbl.col, t.rslt --<--This column name should the same as used in colmns clause in the below query. Its giving error "invalid column". How to handle this case.
FROM tbl, xmltable
(
    'if (contains($X,",")) then ora:tokenize($X,"\,") else $X'
    passing col1 AS X
    columns input_strng varchar2(4000) path '.'
) t
);
return var;
end;

/

Исправление согласно предложению @Alex:

create or replace function splt_fnct(input_strng varchar2)
return var_obj
as
var var_obj:=var_obj();

begin

select obj(tbl.col, t.rslt) 
bulk collect into var
FROM tbl, xmltable
(
    'if (contains($X,",")) then ora:tokenize($X,"\,") else $X'
    passing input_strng AS X
    columns rslt  varchar2(4000) path '.'
) t;

return var;
end;

/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...