Гость
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Вопросы по package/procedure / 25 сообщений из 44, страница 1 из 2
27.11.2019, 17:38
    #39895183
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Пока тренируюсь на кошках.
Хочу сделать процедуру, которая бы выводила в dbms_output отформатированную строку, параметры для которой задаются либо списком, либо хеш-массивом.
Делаю так:
Код: plsql
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 CC_LIBS AS

TYPE VARLIST IS TABLE OF ANYDATA;
TYPE VARHASH IS TABLE OF ANYDATA INDEX BY VARCHAR2(80);

PROCEDURE CC_LOG (args IN VARLIST DEFAULT null);
--PROCEDURE CC_LOG (args IN VARHASH DEFAULT null);

END CC_LIBS;
/

CREATE OR REPLACE PACKAGE BODY CC_LIBS AS

PROCEDURE CC_LOG (args IN VARLIST DEFAULT null) AS
BEGIN
  FOR i IN args.FIRST..args.LAST LOOP
    DBMS_OUTPUT.PUT_LINE('LIST: #'||i);
  END LOOP;
END;

END CC_LIBS;
/



Вызываю так:
Код: plsql
1.
2.
3.
4.
DECLARE
BEGIN
  CC_LIBS.CC_LOG('a','b');
END;



Но не работает, причем никак.
Во первых, не удается перегрузить процедуру для типа VARHASH или просто использовать тип VARHASH. Но это видимо ограничения самого Oracle. В принципе терпимо, меня и простой индексированный список бы устроил.
Но и с ним не работает, при попытке вызвать процедуру получаю ошибку ORA-06550 PLS-00306 (ошибочное число или типы аргументов).
Если попробовать вызвать процедуру без параметров, то возвращает другую ошибку, ORA-06531 (ссылка на неинициализированный набор).
...
Рейтинг: 0 / 0
27.11.2019, 17:49
    #39895190
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
1. Anydata особый тип, поищите примеры использования.
2. Перечень аргументов процедуры не является объектом. Почитайте гайд на предмет инициализации объектов и списков
...
Рейтинг: 0 / 0
27.11.2019, 18:18
    #39895210
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Посмотрел, теперь я вообще не понимаю, зачем нужен anydata.
Я думал, что это для случаев, когда в процедуру может передаваться любой тип — но нет, нужно передавать именно этот тип и тогда уж лучше сразу кастовать в строку.
Получается, что нельзя объявить процедуру с произвольным количеством параметров произвольного типа? Только перечислять arg1, arg2, arg3 и т.д., что сразу же исключает перезагрузку процедуры.
...
Рейтинг: 0 / 0
27.11.2019, 18:21
    #39895213
IMNO
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
произвольным количеством параметров


Нельзя.

Alibek B.
произвольного типа


Можно, но есть нюанс.

Alibek B.
перезагрузку процедуры


Правильно - "перегрузку". Перегрузка в PL/SQL присутствует.
...
Рейтинг: 0 / 0
27.11.2019, 18:26
    #39895216
MazoHist
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
...
Рейтинг: 0 / 0
27.11.2019, 18:51
    #39895225
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
Посмотрел, теперь я вообще не понимаю, зачем нужен anydata.
Я думал, что это для случаев, когда в процедуру может передаваться любой тип — но нет, нужно передавать именно этот тип и тогда уж лучше сразу кастовать в строку.
Получается, что нельзя объявить процедуру с произвольным количеством параметров произвольного типа? Только перечислять arg1, arg2, arg3 и т.д., что сразу же исключает перезагрузку процедуры.

зачем anydata Вам решать

у Вас в процедуре один параметр (таблица)
в таблице может быть произвольное к-во елементов
+ Вы запутались с anydata

при вызове CC_LIBS.CC_LOG тип параметра должен быть varlist
а Вы подсовываете два строковых параметра

зы
загадочный вывод DBMS_OUTPUT.PUT_LINE('LIST: #'||i);

зыы
создавать процедуры с переменым числом параметром показывал Володя Бегун
но я не понял как (мне и не надо было)

....
stax
...
Рейтинг: 0 / 0
27.11.2019, 18:58
    #39895228
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Stax

при вызове CC_LIBS.CC_LOG тип параметра должен быть varlist
а Вы подсовываете два строковых параметра

Это я и имел ввиду, что вместо списка переменных мне нужно передать переменную специального типа со списком значений.
...
Рейтинг: 0 / 0
27.11.2019, 19:03
    #39895231
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
...
Рейтинг: 0 / 0
27.11.2019, 19:06
    #39895232
IMNO
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Stax

создавать процедуры с переменым числом параметром


Например так:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
CREATE OR REPLACE PACKAGE TEST_ARG 
IS
 TYPE t_table_dictionary IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(20);

 PROCEDURE fnc(p_a IN t_table_dictionary);
END TEST_ARG;
/
CREATE OR REPLACE PACKAGE BODY TEST_ARG  
IS
  PROCEDURE fnc(p_a IN t_table_dictionary)
  IS
  BEGIN
    dbms_output.put_line(p_a('Date'));
    dbms_output.put_line(p_a('String'));
    dbms_output.put_line(p_a('Number'));
  END;
END TEST_ARG;
/



Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
DECLARE 
  p_a TEST_ARG.t_table_dictionary;
BEGIN
  p_a('Date')   := TO_CHAR(SYSDATE, 'dd/mm/yyy HH24:MI:SS');
  p_a('String') := 'Test';
  p_a('Number') := TO_CHAR(10.01); 

  TEST_ARG.fnc(p_a => p_a);
END;
...
Рейтинг: 0 / 0
27.11.2019, 19:29
    #39895241
Кобанчег
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
которая бы выводила в dbms_output отформатированную строку
Ну так и передавай массив строк (попутно преобразовывая всё что не строки в строки).

Можно и кучу всего передать одним параметром, но в твоем случае необоснованно.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SQL> create or replace type varlist as table of anydata
  2  /

Type created.

SQL> select xmltype(anydata.convertcollection(varlist(anydata.convertvarchar2('a'),
  2                                                   anydata.convertvarchar2('b'),
  3                                                   anydata.convertcollection(sys.odcinumberlist(1,100,10)),
  4                                                   anydata.convertdate(date '2019-12-01')))).
  5         extract('*').getstringval() x
  6    from dual;

X
--------------------------------------------------------------------------------
<VARLIST><ANYDATA><ANYDATA>a</ANYDATA></ANYDATA><ANYDATA><ANYDATA>b</ANYDATA></A
NYDATA><ANYDATA><ODCINUMBERLIST><NUMBER>1</NUMBER><NUMBER>100</NUMBER><NUMBER>10
</NUMBER></ODCINUMBERLIST></ANYDATA><ANYDATA><ANYDATA>01-DEC-19</ANYDATA></ANYDA
TA></VARLIST>
...
Рейтинг: 0 / 0
27.11.2019, 19:58
    #39895248
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Передавать данные, используя предварительно подготовленный словарь или JSON/XML — это совсем не то же, что вызвать функцию и просто передать в нее список параметров.
Например функция для формирования локализованных сообщений объявлена так:
Код: plsql
1.
2.
3.
    FUNCTION format_message(format IN VARCHAR2 CHARACTER SET ANY_CS,
                           args ...)
      RETURN VARCHAR2 CHARACTER SET format%CHARSET;


Вот это вот args ... и было бы идеальным вариантом, но в самописной процедуре это не срабатывает.
А решение Владимира я честно говоря вообще не понял.
...
Рейтинг: 0 / 0
27.11.2019, 20:42
    #39895255
Кобанчег
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.,

XML был использован только для демонстрации, что можно передать массив хлама как параметр anydata если сильно хочется.

В Oracle нет документированного способа реализовывать varargs.

Что мешает передавать коллекцию строк как один параметр?
...
Рейтинг: 0 / 0
27.11.2019, 21:00
    #39895261
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Для коллекции нужно объявить ее тип, затем объявить переменную, затем заполнить коллекцию и только после этого передать в процедуру/функцию. Это получается слишком многословно, по сравнению с util.format или utl_lms.format_message.
...
Рейтинг: 0 / 0
27.11.2019, 21:29
    #39895265
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
У меня есть такая пачка функций на три основных типа данных (строка/число/дата) в любых сочетаниях:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
FUNCTION FMT(val VARCHAR2, str VARCHAR2 := NULL) RETURN VARCHAR2 IS
BEGIN
  RETURN val;
END;
FUNCTION FMT(val VARCHAR2, str VARCHAR2, zval VARCHAR2) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val VARCHAR2, str VARCHAR2, zval NUMBER) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val VARCHAR2, str VARCHAR2, zval DATE) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val NUMBER, str VARCHAR2 := NULL) RETURN VARCHAR2 IS
BEGIN
  IF (str IS NULL) THEN RETURN TO_CHAR(val); ELSE RETURN TO_CHAR(val, str); END IF;
END;
FUNCTION FMT(val NUMBER, str VARCHAR2, zval VARCHAR2) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val NUMBER, str VARCHAR2, zval NUMBER) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val NUMBER, str VARCHAR2, zval DATE) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val DATE, str VARCHAR2 := NULL) RETURN VARCHAR2 IS
BEGIN
  IF (str IS NULL) THEN RETURN TO_CHAR(val); ELSE RETURN TO_CHAR(val, str); END IF;
END;
FUNCTION FMT(val DATE, str VARCHAR2, zval VARCHAR2) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val DATE, str VARCHAR2, zval NUMBER) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;
FUNCTION FMT(val DATE, str VARCHAR2, zval DATE) RETURN VARCHAR2 IS
BEGIN
  IF (val IS NOT NULL) THEN RETURN FMT(val, str); ELSE RETURN FMT(zval, str); END IF;
END;




Но при таком вызове: cc_libs.fmt(null, 'hh24:mi')
возникает ошибка PLS-00307 (слишком много описаний).
Видимо из-за невозможности сопоставить null с каким-то определенным вариантом; если вместо null использовать переменную или столбец таблицы, то такой неоднозначности нет.
А можно ли это как-то обойти? Например может быть можно было указать вариант для null-значения или указать приоритет?
...
Рейтинг: 0 / 0
27.11.2019, 23:26
    #39895294
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.

Но при таком вызове: cc_libs.fmt(null, 'hh24:mi')
возникает ошибка PLS-00307 (слишком много описаний).


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
SQL> create or replace
  2    package pkg1
  3      is
  4        function f1(p_val number) return number;
  5        function f1(p_val varchar2) return varchar2;
  6        function f1(p_val date) return date;
  7  end;
  8  /

Package created.

SQL> create or replace
  2    package body pkg1
  3      is
  4        function f1(p_val number) return number is begin return p_val; end;
  5        function f1(p_val varchar2) return varchar2 is begin return p_val; end;
  6        function f1(p_val date) return date is begin return p_val; end;
  7  end;
  8  /

Package body created.

SQL> select pkg1.f1(null) from dual
  2  /
select pkg1.f1(null) from dual
       *
ERROR at line 1:
ORA-06553: PLS-307: too many declarations of 'F1' match this call


SQL> select pkg1.f1(to_number(null)) from dual
  2  /

PKG1.F1(TO_NUMBER(NULL))
------------------------


SQL> select pkg1.f1(cast(null as number)) from dual
  2  /

PKG1.F1(CAST(NULLASNUMBER))
---------------------------


SQL> select pkg1.f1(cast(null as date)) from dual
  2  /

PKG1.F1(C
---------


SQL> select pkg1.f1(to_char(null)) from dual
  2  /

PKG1.F1(TO_CHAR(NULL))
----------------------------------------------------------------------------------------------


SQL> 



SY.
...
Рейтинг: 0 / 0
28.11.2019, 09:45
    #39895380
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Подсмотрел Util.Format и сделал свой форматтер.
Точнее еще не сделал, но близко к тому.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
/* ---------------------------------------------------------------------------
  FORMAT (<format string> [, argument list...])
  Форматирование строки в соответствии с шаблоном и передаваемыми данными
  Шаблон обрамляется фигурными или прямоугольными скобками ({} или []).
  В фигурные скобки заключается обычный шаблон.
  В прямоугольные скобки заключается условный шаблон - если в нем отсутствуют 
  значения (равны NULL), то весь шаблон игнорируется (заменяется пустой 
  строкой). Парность скобок не учитывается, тип шаблона определяется по 
  открывающей скобке.
  Символ \ экранирует любой следующий символ. Например \[ используется, чтобы 
  использовать в шаблоне литеральный символ [.
  В шаблоне может быть либо значение, либо вложенный шаблон. Значения всегда 
  предваряются символом $.
  Формат шаблона: "$" index [ "|" format [ "|" nls ] ] [ "@" null ]
  index - порядковый номер аргумента (от 1 до 9) или * (следующий аргумент).
  format - строка формата, передается в to_char() без изменений.
  nls - строка локализации, передается в to_char в зависимости от типа.
  null - используется при пустом значении аргумента
  Примеры:

    Индекс: {$1|FM000000}, город {$2@-}
    Индекс: 012345, город Москва
    Индекс: , город -

    [Трек #{$*|FM00}. ][Альбом '{$*|YYYY} / ]{[{$*} - ]{$*@unknown}}.mp3
    Трек #01. Beatles - Yesterday.mp3
    Альбом '2000 / unknown.mp3

----------------------------------------------------------------------------*/
...
Рейтинг: 0 / 0
28.11.2019, 10:05
    #39895393
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
Код: plsql
1.
FORMAT (<format string> [, argument list...])

Угадывается пока ещё не вздрюченная жизнью наивность.
Alibek B.
Код: plsql
1.
 format - строка формата, передается в to_char() без изменений.

Так и не увидел типа данных.
...
Рейтинг: 0 / 0
28.11.2019, 10:12
    #39895402
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Делать перегрузку для всех возможных сочетаний типов данных 9 аргументов — это как-то перебор. Если найду способ передавать список параметров (желательно произвольного типа), то переделаю, а пока так.
Поэтому все аргументы будут строковыми, а тип данных будет определятся исходя из содержимого и строки формата.
Если строка формата относится к числовым типам, то аргумент будет приводится к числу, то же для даты. Если опознать не удается, будет использоваться как строка.
...
Рейтинг: 0 / 0
28.11.2019, 10:19
    #39895408
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
тип данных будет определятся исходя из содержимого и строки формата.
Наивноватый ты. Особенно с датами.
...
Рейтинг: 0 / 0
28.11.2019, 10:49
    #39895424
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
А пояснить можно, в чем именно?
Я планирую делать так.
1. Если задана строка формата:
1.а. Ищем FM, 9, 0, G, D, точка — если находим, то считаем числом.
1.б. Ищем Y, M, D, HH, MI — если находим, то считаем датой.
2. Проверяем значения:
2.а. Проверяем по некоторым шаблонам (####-##-##, ##.##.####), если совпадает, то считаем датой.
2.б. Проверяем по маске /^\d+$/ (и некоторым другим), если совпадает, то считаем числом.
3. Все остальное считаем строкой.

На все случаи этого недостаточно, но 90% сценариев это закроет, а для остальных случаев нужно будет использовать предварительно отформатированные в нужный формат значения как строки.
...
Рейтинг: 0 / 0
28.11.2019, 11:01
    #39895433
-2-
-2-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
2.а. Проверяем по некоторым шаблонам (####-##-##, ##.##.####), если совпадает, то считаем датой.
Мало "посчитать" датой, нужно еще не потерять исходное значение
Код: plsql
1.
2.
3.
4.
5.
SQL> select cast(sysdate as varchar2(20 char)) thisisdate from dual;

THISISDATE
--------------------------------------------------------------------------------
Какое здесь значение даты?
...
Рейтинг: 0 / 0
28.11.2019, 11:05
    #39895435
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
А при рекурсивном вызове у процедур нет стека?
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
DECLARE

FUNCTION FORMAT(...) RETURN VARCHAR2 IS
...
  tagPos INT := 1; tagOpen INT; tagClose INT; tagOpt INT;
...
BEGIN
...
  LOOP
    tagOpen := INSTR(str, ch, tagPos);
    EXIT WHEN tagOpen = 0;
    tagClose := PAIR(tagOpen);
    tagPos := tagClose + 1;
...
    IF (...) THEN
      tag := FORMAT(...);
    END IF;
...
  END LOOP;
  RETURN res;
END;



У меня такое ощущение, что при рекурсивном вызове FORMAT значение переменной tagPos изменяется в том числе и в родительском контексте. Собственно не ощущение, отладочный вывод именно это и показывает.
В PL/SQL действительно нет стека?
Или я что-то делаю неправильно?
...
Рейтинг: 0 / 0
28.11.2019, 11:07
    #39895438
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
-2-
Какое здесь значение даты?

Ну пользователя совсем за идиота держать не нужно.
Если пользователю удобно использовать автоматическое приведение типов, то он сам предварительно настроит для сессии локаль.
А если он вручную приводит значения с потерей точности, то он видимо знает, что делает, и будет задавать строку формата с учетом своих действий.
...
Рейтинг: 0 / 0
28.11.2019, 11:17
    #39895447
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Alibek B.
Если пользователю удобно использовать
Твой супер-мега-форматтер вызывает конечный пользователь?
...
Рейтинг: 0 / 0
28.11.2019, 11:23
    #39895452
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопросы по package/procedure
Конечный пользователь чего?
Операторы ИС разумеется про него знать не знают.
Он нужен прежде всего для логов и информационных сообщений скриптов, то есть пользователем форматтера будет различная автоматизация, которую обслуживают/настраивают админы ИС.
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Вопросы по package/procedure / 25 сообщений из 44, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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