Кондиционирование с несколькими курсорами - PullRequest
0 голосов
/ 02 мая 2020

У меня есть 5 курсоров, и я пытаюсь создать условную структуру, которая открывает и обрабатывает соответствующий курсор, основываясь на пользовательском вводе. Функция должна собирать результаты в одну строку. Код, очевидно, содержит ошибки, и я не могу на всю жизнь выяснить, где я ошибся. Спасибо, господа за помощь!

create or replace function listnation1(region_name in varchar2)
return varchar2
IS
DECLARE
    CURSOR africaCursor IS 
    SELECT n_name
    FROM nation
    where n_regionkey = 0;

    CURSOR americaCursor IS 
    SELECT n_name
    FROM nation
    where n_regionkey = 1;

    CURSOR asiaCursor IS 
    SELECT n_name
    FROM nation
    where n_regionkey = 2;

    CURSOR europeCursor IS 
    SELECT n_name
    FROM nation
    where n_regionkey = 3;

    CURSOR midEastCursor IS 
    SELECT n_name
    FROM nation
    where n_regionkey = 4;

    aString varchar2 := "";

BEGIN
    IF region_name = "Africa" THEN
        aString := "0   ";
        FOR i in africaCursor LOOP
            CONCAT(aString, str(i.n_name));
            CONCAT(aString, ", ");
        END LOOP;

    ELSIF region_name = "America" THEN LOOP
        aString := "1   ";
        FOR i in americaCursor LOOP
            CONCAT(aString, str(i.n_name));
            CONCAT(aString, ", ");
        END LOOP;

    ELSIF region_name = "Asia" THEN LOOP
        aString := "2   ";
        FOR i in asiaCursor LOOP
            CONCAT(aString, str(i.n_name));
            CONCAT(aString, ", ");
        END LOOP;

    ELSIF region_name = "Europe" THEN LOOP
        aString := "3   ";
        FOR i in europeCursor LOOP
            CONCAT(aString, str(i.n_name));
            CONCAT(aString, ", ");
        END LOOP;

    ELSIF region_name = "Middle East" THEN LOOP
        aString := "4   ";
        FOR i in midEastCursor LOOP
            CONCAT(aString, str(i.n_name));
            CONCAT(aString, ", ");
        END LOOP;
    END IF;

    return aString;
END listnation1;
/

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Вы не используете возвращаемое значение функции concat. Это должно быть что-то вроде

aString := CONCAT(aString, ', ');

Вы также можете написать

aString := aString || i.n_name || ', ';

Обратите внимание также, что разделитель строк - это одиночная кавычка. Двойные кавычки используются для экранирования имен таблиц или столбцов в Oracle.

В SQL вы получаете наилучшую производительность с помощью команд SELECT. Избегайте петель и курсоров, если это возможно.

1 голос
/ 02 мая 2020

5 курсоров, скорее всего, худшее, что вы могли бы написать. По сути, вам вообще не нужны курсоры - LISTAGG может сделать это за один запрос. Вот как:

create or replace function listnation1 (par_region_name in varchar2)
  return varchar2 
is
  retval varchar2(4000);
begin
  select listagg(n.n_name, ',') within group (order by n.n_name)
    into retval
    from nation n
    where n.n_regionkey = case when par_region_name = 'Africa'      then 0
                               when par_region_name = 'America'     then 1
                               when par_region_name = 'Asia'        then 2
                               when par_region_name = 'Europe'      then 3
                               when par_region_name = 'Middle East' then 4
                          end;
  return retval;
end;
/

Если это должно быть решение, связанное с курсором, почему бы не курсор FOR l oop?

create or replace function listnation1 (par_region_name in varchar2)
  return varchar2 
is
  retval varchar2(4000);
begin
  for cur_r in 
   (select n.n_name
    from nation n
    where n.n_regionkey = case when par_region_name = 'Africa'      then 0
                               when par_region_name = 'America'     then 1
                               when par_region_name = 'Asia'        then 2
                               when par_region_name = 'Europe'      then 3
                               when par_region_name = 'Middle East' then 4
                          end
   ) 
  loop
    retval := retval || cur_r.n_name ||',';
  end loop;    

  return rtrim(retval, ',');
end;
/
...