Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Пока тренируюсь на кошках.
Хочу сделать процедуру, которая бы выводила в dbms_output отформатированную строку, параметры для которой задаются либо списком, либо хеш-массивом.
Делаю так:
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;
/


Вызываю так:
DECLARE
BEGIN
  CC_LIBS.CC_LOG('a','b');
END;


Но не работает, причем никак.
Во первых, не удается перегрузить процедуру для типа VARHASH или просто использовать тип VARHASH. Но это видимо ограничения самого Oracle. В принципе терпимо, меня и простой индексированный список бы устроил.
Но и с ним не работает, при попытке вызвать процедуру получаю ошибку ORA-06550 PLS-00306 (ошибочное число или типы аргументов).
Если попробовать вызвать процедуру без параметров, то возвращает другую ошибку, ORA-06531 (ссылка на неинициализированный набор).
27 ноя 19, 17:38    [22026895]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18373
1. Anydata особый тип, поищите примеры использования.
2. Перечень аргументов процедуры не является объектом. Почитайте гайд на предмет инициализации объектов и списков
27 ноя 19, 17:49    [22026907]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Посмотрел, теперь я вообще не понимаю, зачем нужен anydata.
Я думал, что это для случаев, когда в процедуру может передаваться любой тип — но нет, нужно передавать именно этот тип и тогда уж лучше сразу кастовать в строку.
Получается, что нельзя объявить процедуру с произвольным количеством параметров произвольного типа? Только перечислять arg1, arg2, arg3 и т.д., что сразу же исключает перезагрузку процедуры.
27 ноя 19, 18:18    [22026935]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
IMNO
Member

Откуда:
Сообщений: 135
Alibek B.
произвольным количеством параметров


Нельзя.

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


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

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


Правильно - "перегрузку". Перегрузка в PL/SQL присутствует.
27 ноя 19, 18:21    [22026941]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
MazoHist
Member

Откуда:
Сообщений: 145
Alibek B.,

почти printf
27 ноя 19, 18:26    [22026945]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 2795
Alibek B.
Посмотрел, теперь я вообще не понимаю, зачем нужен anydata.
Я думал, что это для случаев, когда в процедуру может передаваться любой тип — но нет, нужно передавать именно этот тип и тогда уж лучше сразу кастовать в строку.
Получается, что нельзя объявить процедуру с произвольным количеством параметров произвольного типа? Только перечислять arg1, arg2, arg3 и т.д., что сразу же исключает перезагрузку процедуры.

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

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

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

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

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

....
stax
27 ноя 19, 18:51    [22026963]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Stax

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

Это я и имел ввиду, что вместо списка переменных мне нужно передать переменную специального типа со списком значений.
27 ноя 19, 18:58    [22026967]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 18373
MazoHist
Alibek B.,
почти printf

А можно ли неопределенное кол-во параметров? как в decode.
27 ноя 19, 19:03    [22026972]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
IMNO
Member

Откуда:
Сообщений: 135
Stax

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


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

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;
/


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;
27 ноя 19, 19:06    [22026975]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Кобанчег
Member

Откуда: Рахів
Сообщений: 841
Alibek B.
которая бы выводила в dbms_output отформатированную строку
Ну так и передавай массив строк (попутно преобразовывая всё что не строки в строки).

Можно и кучу всего передать одним параметром, но в твоем случае необоснованно.
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>


Сообщение было отредактировано: 27 ноя 19, 19:38
27 ноя 19, 19:29    [22026991]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Передавать данные, используя предварительно подготовленный словарь или JSON/XML — это совсем не то же, что вызвать функцию и просто передать в нее список параметров.
Например функция для формирования локализованных сообщений объявлена так:
    FUNCTION format_message(format IN VARCHAR2 CHARACTER SET ANY_CS,
                           args ...)
      RETURN VARCHAR2 CHARACTER SET format%CHARSET;

Вот это вот args ... и было бы идеальным вариантом, но в самописной процедуре это не срабатывает.
А решение Владимира я честно говоря вообще не понял.
27 ноя 19, 19:58    [22027007]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Кобанчег
Member

Откуда: Рахів
Сообщений: 841
Alibek B.,

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

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

Что мешает передавать коллекцию строк как один параметр?

Сообщение было отредактировано: 27 ноя 19, 20:45
27 ноя 19, 20:42    [22027020]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Для коллекции нужно объявить ее тип, затем объявить переменную, затем заполнить коллекцию и только после этого передать в процедуру/функцию. Это получается слишком многословно, по сравнению с util.format или utl_lms.format_message.
27 ноя 19, 21:00    [22027026]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
У меня есть такая пачка функций на три основных типа данных (строка/число/дата) в любых сочетаниях:
+

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-значения или указать приоритет?
27 ноя 19, 21:29    [22027031]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 10051
Alibek B.

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


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.
27 ноя 19, 23:26    [22027094]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Подсмотрел Util.Format и сделал свой форматтер.
Точнее еще не сделал, но близко к тому.
/* ---------------------------------------------------------------------------
  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

----------------------------------------------------------------------------*/


Сообщение было отредактировано: 28 ноя 19, 09:49
28 ноя 19, 09:45    [22027279]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Elic
Member

Откуда:
Сообщений: 29990
Alibek B.
FORMAT (<format string> [, argument list...])
Угадывается пока ещё не вздрюченная жизнью наивность.
Alibek B.
 format - строка формата, передается в to_char() без изменений.
Так и не увидел типа данных.
28 ноя 19, 10:05    [22027306]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Делать перегрузку для всех возможных сочетаний типов данных 9 аргументов — это как-то перебор. Если найду способ передавать список параметров (желательно произвольного типа), то переделаю, а пока так.
Поэтому все аргументы будут строковыми, а тип данных будет определятся исходя из содержимого и строки формата.
Если строка формата относится к числовым типам, то аргумент будет приводится к числу, то же для даты. Если опознать не удается, будет использоваться как строка.
28 ноя 19, 10:12    [22027317]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Elic
Member

Откуда:
Сообщений: 29990
Alibek B.
тип данных будет определятся исходя из содержимого и строки формата.
Наивноватый ты. Особенно с датами.
28 ноя 19, 10:19    [22027325]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
А пояснить можно, в чем именно?
Я планирую делать так.
1. Если задана строка формата:
1.а. Ищем FM, 9, 0, G, D, точка — если находим, то считаем числом.
1.б. Ищем Y, M, D, HH, MI — если находим, то считаем датой.
2. Проверяем значения:
2.а. Проверяем по некоторым шаблонам (####-##-##, ##.##.####), если совпадает, то считаем датой.
2.б. Проверяем по маске /^\d+$/ (и некоторым другим), если совпадает, то считаем числом.
3. Все остальное считаем строкой.

На все случаи этого недостаточно, но 90% сценариев это закроет, а для остальных случаев нужно будет использовать предварительно отформатированные в нужный формат значения как строки.
28 ноя 19, 10:49    [22027359]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
-2-
Member

Откуда:
Сообщений: 15330
Alibek B.
2.а. Проверяем по некоторым шаблонам (####-##-##, ##.##.####), если совпадает, то считаем датой.
Мало "посчитать" датой, нужно еще не потерять исходное значение
SQL> select cast(sysdate as varchar2(20 char)) thisisdate from dual;

THISISDATE
--------------------------------------------------------------------------------
Какое здесь значение даты?
28 ноя 19, 11:01    [22027379]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
А при рекурсивном вызове у процедур нет стека?
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 действительно нет стека?
Или я что-то делаю неправильно?
28 ноя 19, 11:05    [22027382]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
-2-
Какое здесь значение даты?

Ну пользователя совсем за идиота держать не нужно.
Если пользователю удобно использовать автоматическое приведение типов, то он сам предварительно настроит для сессии локаль.
А если он вручную приводит значения с потерей точности, то он видимо знает, что делает, и будет задавать строку формата с учетом своих действий.
28 ноя 19, 11:07    [22027385]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Elic
Member

Откуда:
Сообщений: 29990
Alibek B.
Если пользователю удобно использовать
Твой супер-мега-форматтер вызывает конечный пользователь?
28 ноя 19, 11:17    [22027403]     Ответить | Цитировать Сообщить модератору
 Re: Вопросы по package/procedure  [new]
Alibek B.
Member

Откуда:
Сообщений: 3722
Конечный пользователь чего?
Операторы ИС разумеется про него знать не знают.
Он нужен прежде всего для логов и информационных сообщений скриптов, то есть пользователем форматтера будет различная автоматизация, которую обслуживают/настраивают админы ИС.
28 ноя 19, 11:23    [22027412]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Oracle Ответить