Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / EXECUTE StoredProcedure... / 25 сообщений из 29, страница 1 из 2
10.06.2003, 17:33:36
    #32180743
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Переходя с MSSQL на Oracle, спотыкаешься на каждом элементарном действии. Создаю хранимую процедуру (для теста упрощенный вариант):
Код: plaintext
1.
2.
3.
4.
CREATE OR REPLACE PROCEDURE  "GetDBParamsById"  (ParamId IN number)
AS BEGIN
  EXECUTE IMMEDIATE 'SELECT * FROM "TDBParams" WHERE F_PARAMID = ParamId';
END;

Процедура создается без ошибок. Но когда пытаюсь выполнить ее через SQL+:
Код: plaintext
1.
EXECUTE  "GetDBParamsById"  ( 234 );

Возвращается ругань:
Код: plaintext
1.
2.
3.
4.
ошибка в строке  1 :
ORA- 00904 :  "PARAMID" : недопустимый идентификатор
ORA- 06512 : на   "TESTUSR.GETDBPARAMSBYID" , line  3 
ORA- 06512 : на  line  1 

Что я делаю не так?
...
Рейтинг: 0 / 0
10.06.2003, 18:14:40
    #32180789
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
во первых наверное надо быть взять ParamId тоже в кавычки. Оракл преобразует имена в верхний регистр, чтобы это предотвратить надо брать их в кавычки.

CREATE OR REPLACE PROCEDURE "GetDBParamsById" ("ParamId" IN number)
AS BEGIN
EXECUTE IMMEDIATE 'SELECT * FROM "TDBParams" WHERE F_PARAMID = : ParamId' using "ParamId";
END;
...
Рейтинг: 0 / 0
10.06.2003, 18:15:11
    #32180792
Alex623
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
EXECUTE IMMEDIATE 'SELECT * FROM "TDBParams" WHERE F_PARAMID = '||ParamId;
...
Рейтинг: 0 / 0
10.06.2003, 18:23:26
    #32180803
AndrewS
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
create table params
(	param_id	number
,	param_nm	varchar2( 100 )
);

insert into params values(  1 , 'one');

create or replace procedure GetDBParamsByID
( p_paramID in number
) as
  sParamNm	varchar2( 100 );
begin
  execute immediate 'select param_nm from params where param_id = :ParamID'
  into sParamNm
  using p_paramID;

  dbms_output.put_line('Param NM: ' || sParamNm);
end;

SQL> set serveroutput on
SQL> exec getDBParamsByID( 1 );
Param NM: one
...
Рейтинг: 0 / 0
10.06.2003, 18:28:35
    #32180810
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
А как лучше

execute immediate 'select param_nm from params where param_id = :ParamID'

или

EXECUTE IMMEDIATE 'SELECT * FROM "TDBParams" WHERE F_PARAMID= ' || ParamId;

Первый вариант снижает количество hard parse?
...
Рейтинг: 0 / 0
10.06.2003, 18:32:31
    #32180813
MaxU
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
на синтаксические ошибки вам уже указали, но главная ошибка, ИМХО - идеологическая!

Oracle не позволяет делать простой SELECT (с выводом результата клиенту !) в PL/SQL блоке, коим является любая процедура

почитайте о REF CURSOR
...
Рейтинг: 0 / 0
10.06.2003, 18:34:04
    #32180814
LG
LG
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
2 Violina
Лучше 1
...
Рейтинг: 0 / 0
10.06.2003, 18:44:17
    #32180821
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
2 Violina:

Yes, you are correct it will reduce number of hard parses. However, in some cases, using bind variable in CBO can limit CBO abilities to choose "best" plan. For example:

Код: plaintext
SELECT ename FROM emp WHERE empno >  9999 ; 

and
Код: plaintext
SELECT ename FROM emp WHERE empno > :bind1; 

Assuming table emp has been analyzed, CBO knows the HIGH and LOW values of 'EMPNO'. For the first of these statements CBO can determine a 'selectivity' of the clause 'WHERE empno > 9999', but for the second it does not know if ':bind1' is '1' or '9999' and thus uses a default selectivity. This is true even when using histograms as CBO does NOT KNOW the value of the bind variable. Hence, the resulting execution plans can be very different.

SY
...
Рейтинг: 0 / 0
11.06.2003, 10:50:24
    #32181058
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Спасибо за ответы, но вопрос не особо прояснился.
Но самый главный вопрос:
Мне нужна технология использования хранимых процедур, для которых в результате можно получить ADO Recordset (обычно на основе использования Command(имя SP). Кто-нибудь, кто использует ADO, наверняка уже решал такую проблеиму?
1. Как я понял, лучше сразу писать имена параметров в верхнем регистре, во избежание дальнейших проблем.
2. Вопрос в том, как вернуть данные: использование курсора в MSSQL я всегда старался избегать, т.к. это лишние "тормоза". Разве в Oracle это не так?
3. К тому же, практически взятый один в один пример из доки не желает работать:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE OR REPLACE PROCEDURE  "GetDBParamsById"  (PARAMID IN number)
AS
CURSOR cur_tdbparams IS SELECT * FROM  "TDBParams"  WHERE F_PARAMID = PARAMID;
BEGIN
FOR cur_tdbparams IN cur_tdbparams LOOP
  DBMS_OUTPUT.put_line(cur_tdbparams.F_PARAMID);
END LOOP;
CLOSE cur_tdbparams;
END;

Line # =  5  Column # =  22  Error Text = PLS- 00364 : недопустимое использование циклической индексной переменной 'CUR_TDBPARAMS'
...
Рейтинг: 0 / 0
11.06.2003, 11:05:50
    #32181079
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
to SY

Все как всегда оказалось не однозначным.

to Finder

CREATE OR REPLACE PROCEDURE "GetDBParamsById" (PARAMID IN number)
AS
CURSOR cur_tdbparams IS SELECT * FROM "TDBParams" WHERE F_PARAMID = PARAMID;
BEGIN
FOR cur_tdbparams IN cur_tdbparams LOOP
DBMS_OUTPUT.put_line(cur_tdbparams.F_PARAMID);
END LOOP;
CLOSE cur_tdbparams; убрать !!! конструкция FOR сама закрывает курсор
END;

PS
Странно думала что вместо AS надо IS писать, но и с AS тоже работает. Это что альтернативный синтаксис?

to all

использование курсора в MSSQL я всегда старался избегать, т.к. это лишние "тормоза". Разве в Oracle это не так?

А можно в Оракл как то еще кроме как курсором фетчить данные на клиенте? Насколько я поняла при любом селекте используется курсор, просто неявно, или это не так?
...
Рейтинг: 0 / 0
11.06.2003, 11:11:20
    #32181088
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
to Finder

Да и еще

FOR cur_tdbparams IN cur_tdbparams LOOP

используй другое имя для переменной не совпадающее с курсором.

PS
Где ж ты такую доку нашел?:-)
...
Рейтинг: 0 / 0
11.06.2003, 11:37:15
    #32181118
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Гм... С именем переменной действительно ошибочка вышла.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
CREATE OR REPLACE PROCEDURE  "GetDBParamsById"  (PARAMID IN number)
AS
CURSOR cur_tdbparams IS SELECT * FROM  "TDBParams"  WHERE F_PARAMID = PARAMID;
BEGIN
FOR var_tdbparams IN cur_tdbparams LOOP
  DBMS_OUTPUT.put_line(var_tdbparams.F_PARAMID);
END LOOP;
END;

При запуске из SQL+
Код: plaintext
1.
2.
EXECUTE  "TDBParams"  ( 245 )
пишет  "Процедура PL/SQL успешно завершена." 

- а данных не выводит!!! Если же напрямую написать
SELECT * FROM "TDBParams" WHERE F_PARAMID = 245;
запись нормально возвращается.
1. В чем дело?
2. Как вывести все поля записи, не приьегая к явному их перечислению, что то типа DBMS_OUTPUT.put_line(var_tdbparams.*) ???
...
Рейтинг: 0 / 0
11.06.2003, 11:54:23
    #32181153
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
единственное предположение, что в твоей таблице есть поле PARAMID, тогда используется оно а не параметр PARAMID.

Вот пример работающей процедуры, смотри по нему

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
SQL> CREATE OR REPLACE PROCEDURE TEST_PROC(PARAMID IN number)
   2    AS
   3    CURSOR tst_cursor IS SELECT DUMMY FROM DUAL WHERE  9  = PARAMID;
   4    BEGIN
   5    FOR rec IN tst_cursor LOOP
   6      DBMS_OUTPUT.put_line(rec.DUMMY);
   7    END LOOP;
   8    END;
   9    /


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
SQL> set serverout on
SQL> execute test_proc( 8 );

PL/SQL procedure successfully completed.

SQL> execute test_proc( 9 );
X

PL/SQL procedure successfully completed.
...
Рейтинг: 0 / 0
11.06.2003, 11:55:06
    #32181154
Denis Popov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
1.\r
Код: plaintext
1.
2.
3.
\r
set serveroutput on\r
exec dbms_output.enable( 20000 );\r
\r
\r
2. А куда и где именно все это надо вывести? Упоминалось ADO, вот это не поможет? /topic/31528
...
Рейтинг: 0 / 0
11.06.2003, 12:02:32
    #32181164
Violina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Если же напрямую написать
SELECT * FROM "TDBParams" WHERE F_PARAMID = 245;


я подумала что ты имеешь ввиду

CURSOR cur_tdbparams IS SELECT * FROM "TDBParams" WHERE F_PARAMID = 245;

И при этом не выводится. А так ser serverout on должно помочь.
...
Рейтинг: 0 / 0
11.06.2003, 14:46:48
    #32181385
Владимир П.
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
> Странно думала что вместо AS надо IS писать, но и с AS тоже работает. Это что альтернативный синтаксис?

Разницы нет. Синтаксис PL/SQL создавался на основе Ады, в которой принято IS. AS -- это ближе к стандарту SQL.
...
Рейтинг: 0 / 0
11.06.2003, 16:02:08
    #32181495
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
SET SERVEROUT ON вроде помогло, а на указанный в одном из линков вариант \r
SET SERVEROUTPUT ON 1000000 шла ругань на неверный параметр "1000000".\r
\r
В общем, что-то уже начинает получаться. Для работы с хранимой процедурой, возвращающей набор записей (и обработкой его в Recordset):\r
\r
1. Создаем пакет с типом курсора\r
Код: plaintext
1.
2.
3.
4.
5.
\r
CREATE OR REPLACE PACKAGE MyPack AS\r
TYPE TCursor IS REF CURSOR;\r
PROCEDURE GetData (Cur TCursor);\r
END MyPack;\r
\r
\r
2. Создаем ХП, возвращающую REF CURSOR (одно неудобство - чтобы потом протестировать работу ХП в SQL+, в SELECT приходится явно перечислять поля) - как-то все же можно это ограничение обойти?\r
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
\r
CREATE OR REPLACE PROCEDURE GetDBParamsData (ParamId IN number,Cur OUT MyPack.TCursor)\r
AS\r
BEGIN\r
OPEN Cur FOR \r
SELECT * FROM  "TDBParams"  WHERE F_PARAMID=ParamId;\r
END;\r
\r
\r
3. Если в ХП явно перечислить поля, ее работу можно протестировать по SQL+:\r
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
\r
set serverout on\r
DECLARE \r
v_cursor MyPack.TCursor; \r
v_name  "TDBParams" .F_NAME%TYPE; \r
v_paramid  "TDBParams" .F_PARAMID%TYPE;\r
BEGIN \r
GetDBParamsData ( 245 ,v_cursor); \r
LOOP \r
FETCH v_cursor \r
INTO v_name; \r
EXIT WHEN v_cursor%NOTFOUND; \r
DBMS_OUTPUT.PUT_LINE(v_name || \' | \' || v_paramid); \r
END LOOP; \r
CLOSE v_cursor; \r
END;\r
\r
\r
4. Заполнить ADO Recordset можно несколько извращенным (с моей точки зрения) способом:\r
Код: plaintext
1.
2.
3.
\r
pRecordset->Open(_btsr_t( "BEGIN GETDBPARAMSDATA (245 ,CUR); END;"),\\\r
vConnection,adOpenKeyset, adLockBatchOptimistic, adCmdText));\r
\r
Работает! Но хотелось бы разобраться с получением Recordser через Command.\r
:(\r
\r
5. А вот получить ADO Recordset на основе Command не получается. В стандартном варианте (как это работает с MSSQL) в Command (перед Execute) генерируется строка Command->CommandText вида:\r
Код: plaintext
1.
2.
\r
 "{ call GETDBPARAMSDATA(?)}:PARAMID=245 ,"\r
\r
- в таком варианте конечно идет ругань о несоответсвии параметров. Здесь каким-то образом надо предварительно добавить выходной параметр типа REF CURSOR - но КАК ЭТО СДЕЛАТЬ???!!!\r
\r
В /topic/31528 каким-то шаманством с классом TestResultSet это было достигнуто за счет CallableStatement stmt = conn.prepareCall("BEGIN GetEmpRS(?, ?); END;"); \r
stmt.setInt(1, 30); // DEPTNO \r
stmt.registerOutParameter(2, OracleTypes.CURSOR); //REF CURSOR \r
... но мне эти действия непонятны... к тому же VBA а не VC...
...
Рейтинг: 0 / 0
11.06.2003, 16:19:18
    #32181524
Denis Popov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
За ADO не скажу, не работал, а в SQLPlus тестирование таких вещей несколько проще (SYS_REFCURSOR - оракловый тип, появившийся в Oracle 9i, иначе подставляй свой пекетный):

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
create or replace procedure get_emp (
  p_cr out sys_refcursor
) as
begin
  open p_cr for
    select e.* from scott.emp e;
end;
/
var result refcursor
exec get_emp(:result);
print :result
...
Рейтинг: 0 / 0
11.06.2003, 16:33:06
    #32181543
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Тестирование резултатов ХП так действительно работает, и код намного короче. Спасибо!
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
set serverout on
var result refcursor;  -- For Oracle9i only
 
 --var result MyPack.TCursor; -- For old Oracle version
 
exec GetDBParamsData( 245 ,:result);
print :result;

А вот что делать с ADO Command? Есть версия что надо устанавливать Command->Properties("PLSQLRSet")->Value = COleVariant(true); - только вот свойтсва я такого у Command не нашел. Кто-нибудь работал с ADO?
...
Рейтинг: 0 / 0
11.06.2003, 16:40:08
    #32181559
Denis Popov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Ты перепутал REFCURSOR и SYS_REFCURSOR. Первое - специальное слово SQL*Plus, второе- тип PL/SQL. Сравни, в 8i придется написать так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
create or replace package pkg_test as
  type t_refcursor is ref cursor;
  procedure get_emp (
    p_cr out t_refcursor
  );
end;
/

create or replace package body pkg_test as
  procedure get_emp (
    p_cr out t_refcursor
  ) as
  begin
    open p_cr for
      select e.* from scott.emp e;
  end;
end;
/

var result refcursor
exec pkg_test.get_emp(:result);
print :result
...
Рейтинг: 0 / 0
11.06.2003, 17:15:39
    #32181594
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Я еще много чего путаю. ;)
Например, какую команду все же давать для вывода результатов:
Код: plaintext
1.
2.
3.
4.
set serverout on;
set serveroutput on;
set serveroutput on  1000000 ;  -- так тоже было в одном из постингов
 

?

А по поводу использования Command с REF CURSOR народ молчит. Видимо, или никто не работает с Oracle через ADO, или топик уже слишком большой и никто его не читает...
:(
...
Рейтинг: 0 / 0
11.06.2003, 17:29:04
    #32181604
Denis Popov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Смотри:
SQL*Plus User's Guide and Reference
SET SERVEROUT[PUT]
http://technet.oracle.com/docs/products/oracle9i/doc_library/release2/server.920/a90842/ch13.htm#1012919

А про работу Command с REF CURSOR скорее ответят в форумах по Visual C++, либо в туториалах. На MSDN-то ничего нет?
...
Рейтинг: 0 / 0
11.06.2003, 17:32:22
    #32181608
.dba
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
блин, нельзя ж быть таким ленивым - первая же ссылка на гугле по "REF CURSOR ADO":
http://www.google.com.ru/search?q=cache:5jg89SZ-7NEJ:doug.burns.tripod.com/ado.doc+REF+CURSOR+ado&hl=ru&ie=UTF-8
...
Рейтинг: 0 / 0
11.06.2003, 20:22:04
    #32181722
are
are
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
set serveroutput on;

или set serveroutput on size 10000

набери в SQL Plus
help set


test@ORCL.LOCAL>; help set

получишь описание команды set
...
SERVEROUT[PUT] {ON|OFF}
[SIZE n] [FOR[MAT]
{WRA[PPED] |
WOR[D_WRAPPED] |
TRU[NCATED]}]
...
...
Рейтинг: 0 / 0
12.06.2003, 13:43:51
    #32181916
Finder
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
EXECUTE StoredProcedure...
Спасибо за ссылки. С SQL+ все понятно, а вот по ADO + REF CURSOR...
Проблемы...
В приведенной выше ссылке речь шла о провайдере OraOLEDB.Oracle (и там действительно проблема решается устновкой свойства "PLSQLRSet").
В моем же случае надо заставить поддерживать REF CURSOR объект Command для MSDAORA.1! Так что заранее прошу прощения за подробности применения ADO...

На буржуйских сайтах предлагают решить проблему с REF CURSOR для Command по-разному:

1. Кто-то скачивает некую утилиту для MSDAORA с http://www.aboves.com/downloads, после этого CommandText перед Execute() приобретает вид типа "begin GETPARAMSDATA (?,{resultset 0,CUR})}". Но этот вариант мне не понравился - какая-то внешняя программа...

2. Кто-то просто подменяет CommandText, т.е. зная заранее о необходимости поддержки REF CURSOR, можно
Код: plaintext
1.
2.
3.
4.
считать CommandText 
 "{ call GETPARAMSDATA (?)}: PARAMID=245 ,"
и заменить его на 
 "{ call GETPARAMSDATA (?,{resultset 0 ,CUR}) }: PARAMID= 245 ,"

казалось бы, все просто, но сделать это невозможно. Дело в том что PutCommandText() производит дополнительный парсинг - добавляет слева "{ call" и справа "(?) }: PARAMID=245, ". В итоге при выполнении поучается полная ерунда:
Код: plaintext
1.
2.
 "{ call { call GETPARAMSDATA (?,{resultset 0 ,CUR}) }: PARAMID= 245 ,}: 
PARAMID= 245 , "

Если установить adCmdText, при дополнительном парсинге добавляются только значения параметров, но там другой синтаксис и куда поместить "{resultset 0,CUR}" совершенно непонятно...

Единственный случай, когда вариант 2 заработал - если никаких параметров, кроме REF CURSOR, не требуется. Вариант с подменой CommandText при adCmdStoredProc на "GETPARAMSDATA ({resultset 0,CUR})" работает прекрасно.

Но в итоге - использовать подмену CommandText тольком не удалось.

3. Предлагалось заранее зачитывать инфу о параметрах процедуры:
Код: plaintext
1.
2.
pCommand->Prepared = VARIANT_TRUE;
pCommand->Parameters->Refresh();

однако это не помогло, т.к. хотя Command и узнает о наличии параметра REF CURSOR, что с ним делать он совершенно не знает и формирует CommandText вида (пример при ХП с одним параметров - REF CURSOR):
Код: plaintext
1.
 "{ call GETDATA(?)}: CUR=NULL, " 

такая гениальная строка конечно приводит к ошибке "неверное имя/номер переменной". Так что тоже не помогло.

Народ! По-прежнему надеюсь на вашу помощь!!!
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / EXECUTE StoredProcedure... / 25 сообщений из 29, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]