Как отобразить результаты процедуры вне ее в Oracle - PullRequest
0 голосов
/ 26 ноября 2018

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

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

Чтобы сократить вопрос, я сократил количество столбцов в HR.

Идентификатор таблицы HR, GROUP_NAME и GROUP_LEVEL.Таблица Drill имеет ID и TYPEVALUE.

CREATE OR REPLACE PROCEDURE DOCSADM.DRILL_RECORD_POSITION (
    RECORD_TYPE IN VARCHAR2,
    OUT_ID OUT VARCHAR2,
    OUT_GROUP_NAME OUT VARCHAR2,
    OUT_GROUP_LEVEL OUT VARCHAR2
) AS
BEGIN
    SELECT  HR.ID,  HR.GROUP_NAME,  HR.GROUP_LEVEL
    INTO    OUT_ID, OUT_GROUP_NAME, OUT_GROUP_LEVEL
    FROM HR_POSITION HR JOIN DRILL_POSITION DP ON (HR.ID = DP.ID) WHERE DP.TYPEVALUE = RECORD_TYPE;
END DRILL_RECORD_POSITION;

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

Петли

BEGIN
for t in (DRILL_RECORD_POSITION('D', V1,V5,V6))
loop
    --dbms_output.put_line(t.V1 || t.V5 || t.V6);
    dbms_output.put_line(t.OUT_ID);

end loop;
END;
/

КУРСОРЫ

DECLARE
V1 HR_POSITION.ID%TYPE;
V5 HR_POSITION.GROUP_NAME%TYPE;
V6 HR_POSITION.GROUP_LEVEL%TYPE;
CURSOR T_CUR IS DRILL_RECORD_POSITION('D', V1,V5,V6);
BEGIN
OPEN T_CUR;
    DBMS_OUTPUT.PUTLINE('START');
    LOOP
        FETCH T_CUR INTO V1,V5,V6;
        EXIT WHEN T_CUR%NOTFOUND;
        DBMS_OUTPUT.PUTLINE(V1||V5||V6);
    END LOOP;
CLOSE T_CUR;
END;

ДЛЯ ЦИКЛОВ

DECLARE
V1 HR_POSITION.POSITION_ID%TYPE;
V5 HR_POSITION.GROUP_NAME%TYPE;
V6 HR_POSITION.GROUP_LEVEL%TYPE;
BEGIN
    DBMS_OUTPUT.PUTLINE('START');
    FOR INDEX IN (DRILL_RECORD_POSITION('D', V1,V5,V6))
LOOP
        --DBMS_OUTPUT.PUTLINE(INDEX.ID);
        DBMS_OUTPUT.PUTLINE(INDEX.V1||INDEX.V5||INDEX.V6);
    END LOOP;

END;

Примечание: я отредактировал имена столбцов и укоротил некоторые при передаче сюда, чтобы я мог сделать несколько ошибок.

Все статьи, которые я видел в Интернете, показывают мне, как отображать из оригинальной процедуры или с помощьюпредставления, курсоры, записи.Если я не ошибаюсь, у Eclipse не будет проблем с использованием информации в текущей форме, поэтому я передаю ее таким образом.Поэтому я не заинтересован в изменении процедуры и хотел бы работать с ней как есть, так как приложение будет это делать.

Поскольку это первая из хранимых процедур, которые я выполняю для приложениявместо использования запросов adhoc из приложения у меня нет существующих примеров для работы, поэтому я считаю, что результаты будут работать нормально, потому что это должен быть тот же формат, который используют adhoc.

Обновление:

В одном из комментариев я указал на то, что должно было быть решением .Это было подтверждено другим решением , которое находилось под ним.

Я получаю сообщение об ошибке

ORA-01422: точная выборка возвращает больше, чем запрошенное количество строк

Итак, я возвращаю несколько строк, но это мое ожидание и то, что происходит.Я просто не могу понять, как отобразить результаты.

1 Ответ

0 голосов
/ 03 декабря 2018

Чтобы протестировать показанную вами процедуру, вы должны сделать что-то вроде:

declare
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  drill_record_position('D', l_id, l_group_name, l_group_level);
  dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
end;
/

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

Так что на самом деле это похоже на ваш вопросдолжно быть о том, как написать вашу процедуру, чтобы она работала с одним из методов поиска / тестирования, которые вы пробовали.

Если вашей процедуре нужно возвращать несколько строк, она может использовать курсор ref, например:

create or replace procedure drill_record_position (
  p_record_type in varchar2,
  p_ref_cursor out sys_refcursor
)
as
begin
  open p_ref_cursor for
    select hr.id, hr.group_name, hr.group_level
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type;
end drill_record_position;
/

, который можно затем протестировать с помощью чего-то вроде:

declare
  l_ref_cursor sys_refcursor;
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  drill_record_position('D', l_ref_cursor);
  loop
    fetch l_ref_cursor into l_id, l_group_name, l_group_level;
    exit when l_ref_cursor%notfound;
    dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
  end loop;
  close l_ref_cursor;
end;
/

Вы также можете сделать это как функцию, с которой может быть проще работать из вашего приложения:

-- drop procedure drill_record_position;

create or replace function drill_record_position (p_record_type in varchar2)
return sys_refcursor as
  l_ref_cursor sys_refcursor;
begin
  open l_ref_cursor for
    select hr.id, hr.group_name, hr.group_level
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type;
  return l_ref_cursor;
end drill_record_position;
/

declare
  l_ref_cursor sys_refcursor;
  l_id hr_position.id%type;
  l_group_name hr_position.group_name%type;
  l_group_level hr_position.group_level%type;
begin
  l_ref_cursor := drill_record_position('D');
  loop
    fetch l_ref_cursor into l_id, l_group_name, l_group_level;
    exit when l_ref_cursor%notfound;
    dbms_output.put_line(l_id ||':'|| l_group_name ||':'|| l_group_level);
  end loop;
  close l_ref_cursor;
end;
/

Вы также можете сделать это с коллекциями и конвейерной функцией, которую необходимо настроить:

create type t_drill_obj as object (
   -- use your real data types...
  id number,
  group_name varchar2(10),
  group_level number
)
/

create type t_drill_tab as table of t_drill_obj
/

create or replace function drill_record_position (p_record_type in varchar2)
return t_drill_tab pipelined as
begin
  for l_row in (
    select t_drill_obj(hr.id, hr.group_name, hr.group_level) as obj
    from hr_position hr
    join drill_position dp
    on hr.id = dp.id
    where dp.typevalue = p_record_type
  )
  loop
    pipe row (l_row.obj);
  end loop;
  return;
end drill_record_position;
/

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

select * from table(drill_record_position('D'));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...