powered by simpleCommunicator - 2.0.29     © 2024 Programmizd 02
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пару вопросов по табличной функции
30 сообщений из 30, показаны все 2 страниц
Пару вопросов по табличной функции
    #40105259
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Обычная потоковая табличная функция, которая используется в SQL запросе с оператором table.
Если объектный тип и вложенная таблица определены на уровне схемы, все ок. Если в пакете - выдает ошибку.
Вот здесь https://oracle-base.com/articles/misc/pipelined-table-functions нашел: "Regular table functions require named row and table types to be created as database objects.". Но почему - не объясняется.

Вопрос 1. Почему так происходит? Интересует суть, почему объявление на уровне пакета не работает, а на уровне схемы - работает.
Вопрос 2. Можно ли в примере ниже заменить явное присваивание полей присваиванием на уровне записи с использованием bulk collect? У меня не получилось (из-за того, что если объявить два типа коллекций с одинаковыми определениями, получаем два разных типа данных, и переменные одного типа нельзя присвоить переменным другого типа).

Заранее благодарю)

Определение на уровне схемы (отрабатывает нормально):
Код: 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.
-- USER-DEFINED OBJECT TYPE AND NESTED TABLE - WORKS GOOD

-- USER-DEFINED OBJECT TYPE
CREATE OR REPLACE TYPE EMP_OT AS OBJECT
(
  EMPNO    NUMBER(12),
  ENAME    VARCHAR2(10),
  JOB      VARCHAR2(9),
  MGR      NUMBER(4),
  HIREDATE DATE,
  SAL      NUMBER(7,2),
  COMM     NUMBER(7,2),
  DEPTNO   NUMBER(2)
);
/
-- USER DEFINED NESTED TABLE 
CREATE OR REPLACE TYPE EMP_AAT IS TABLE OF EMP_OT;
/
-- PACKAGE DEFINED REF CUR TYPE
CREATE OR REPLACE PACKAGE TYPE_DEF_PKG 
AS
  TYPE EMP_RCT IS REF CURSOR RETURN EMP%ROWTYPE;
END;
/
-- TABLE FUNCTION
CREATE OR REPLACE FUNCTION TBL_FUNC (CV_IN IN TYPE_DEF_PKG.EMP_RCT)
RETURN EMP_AAT
IS
  L_ROW_AS_OBJECT EMP_OT := EMP_OT(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  L_ROW_FROM_QUERY CV_IN%ROWTYPE;
  RETVAL EMP_AAT := EMP_AAT();
BEGIN
  LOOP
    FETCH CV_IN INTO L_ROW_FROM_QUERY;
    EXIT WHEN CV_IN%NOTFOUND;
    
    L_ROW_AS_OBJECT.EMPNO := L_ROW_FROM_QUERY.EMPNO;
    L_ROW_AS_OBJECT.ENAME := L_ROW_FROM_QUERY.ENAME;
    L_ROW_AS_OBJECT.JOB := L_ROW_FROM_QUERY.JOB;
    L_ROW_AS_OBJECT.MGR := L_ROW_FROM_QUERY.MGR;
    L_ROW_AS_OBJECT.HIREDATE := L_ROW_FROM_QUERY.HIREDATE;
    L_ROW_AS_OBJECT.SAL := L_ROW_FROM_QUERY.SAL;
    L_ROW_AS_OBJECT.COMM := L_ROW_FROM_QUERY.COMM;
    L_ROW_AS_OBJECT.DEPTNO := L_ROW_FROM_QUERY.DEPTNO;
    
    RETVAL.EXTEND;
    RETVAL(RETVAL.LAST) := L_ROW_AS_OBJECT;
  END LOOP;
  
  CLOSE CV_IN;
  
  RETURN RETVAL;
END;
/
-- SELECT USING TABLE OPERATOR
SELECT * 
FROM TABLE(TBL_FUNC(CURSOR(SELECT * FROM EMP)));
/



Определение на уровне пакета (выдает ошибку):
Код: 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.
-- PACKAGE-DEFINED OBJECT TYPE AND NESTED TABLE - DOESNT WORK
CREATE OR REPLACE PACKAGE TYPE_DEF_PKG 
AS
  TYPE EMP_RCT IS REF CURSOR RETURN EMP%ROWTYPE;
  TYPE EMP_RT IS RECORD (
                        EMPNO    NUMBER(12),
                        ENAME    VARCHAR2(10),
                        JOB      VARCHAR2(9),
                        MGR      NUMBER(4),
                        HIREDATE DATE,
                        SAL      NUMBER(7,2),
                        COMM     NUMBER(7,2),
                        DEPTNO   NUMBER(2)
                      );
  TYPE EMP_NTT IS TABLE OF EMP_RT;
END;
/
-- TABLE FUNCTION
CREATE OR REPLACE FUNCTION TBL_FUNC (CV_IN IN TYPE_DEF_PKG.EMP_RCT)
RETURN TYPE_DEF_PKG.EMP_NTT
IS
  L_ROW TYPE_DEF_PKG.EMP_RT; 
  L_ROW_FROM_QUERY CV_IN%ROWTYPE;
  RETVAL TYPE_DEF_PKG.EMP_NTT := TYPE_DEF_PKG.EMP_NTT();
BEGIN
  LOOP
    FETCH CV_IN INTO L_ROW_FROM_QUERY;
    EXIT WHEN CV_IN%NOTFOUND;
    
    L_ROW.EMPNO := L_ROW_FROM_QUERY.EMPNO;
    L_ROW.ENAME := L_ROW_FROM_QUERY.ENAME;
    L_ROW.JOB := L_ROW_FROM_QUERY.JOB;
    L_ROW.MGR := L_ROW_FROM_QUERY.MGR;
    L_ROW.HIREDATE := L_ROW_FROM_QUERY.HIREDATE;
    L_ROW.SAL := L_ROW_FROM_QUERY.SAL;
    L_ROW.COMM := L_ROW_FROM_QUERY.COMM;
    L_ROW.DEPTNO := L_ROW_FROM_QUERY.DEPTNO;
    
    RETVAL.EXTEND;
    RETVAL(RETVAL.LAST) := L_ROW;
  END LOOP;
  
  CLOSE CV_IN;
  
  RETURN RETVAL;
END;
/
-- SELECT USING TABLE OPERATOR
SQL> SELECT *
  2  FROM TABLE(TBL_FUNC(CURSOR(SELECT * FROM EMP)));
FROM TABLE(TBL_FUNC(CURSOR(SELECT * FROM EMP)))
           *
ERROR AT LINE 2:
ORA-00902: INVALID DATATYPE
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105314
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Давно не брал я в руки шашку...

ArchiSQL,

авторВопрос 1. Почему так происходит? Интересует суть, почему объявление на уровне пакета не работает, а на уровне схемы - работает.

By design, смиритесь. Видимо возникнут проблемы с грантами и областями видимости.

авторВопрос 2. Можно ли в примере ниже заменить явное присваивание полей присваиванием на уровне записи с использованием bulk collect? У меня не получилось (из-за того, что если объявить два типа коллекций с одинаковыми определениями, получаем два разных типа данных, и переменные одного типа нельзя присвоить переменным другого типа).


А если так?
Код: 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.
Определение на уровне схемы (отрабатывает нормально):
-- USER-DEFINED OBJECT TYPE AND NESTED TABLE - WORKS GOOD

-- USER-DEFINED OBJECT TYPE
CREATE OR REPLACE TYPE EMP_OT AS OBJECT
(
  EMPNO    NUMBER(12),
  ENAME    VARCHAR2(10),
  JOB      VARCHAR2(9),
  MGR      NUMBER(4),
  HIREDATE DATE,
  SAL      NUMBER(7,2),
  COMM     NUMBER(7,2),
  DEPTNO   NUMBER(2)
);
/
-- USER DEFINED NESTED TABLE 
CREATE OR REPLACE TYPE EMP_AAT IS TABLE OF EMP_OT;
/
-- PACKAGE DEFINED REF CUR TYPE
CREATE OR REPLACE PACKAGE TYPE_DEF_PKG 
AS
  TYPE EMP_RCT IS REF CURSOR RETURN EMP_OT;
END;
/
-- TABLE FUNCTION
CREATE OR REPLACE FUNCTION TBL_FUNC (CV_IN IN TYPE_DEF_PKG.EMP_RCT)
RETURN EMP_AAT
IS
  L_ROW_AS_OBJECT EMP_OT := EMP_OT(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  RETVAL EMP_AAT := EMP_AAT();
BEGIN
  LOOP
    FETCH CV_IN BULK COLLECT INTO RETVAL;
    EXIT WHEN CV_IN%NOTFOUND;
  END LOOP;
  
  CLOSE CV_IN;
  
  RETURN RETVAL;
END;
/
-- SELECT USING TABLE OPERATOR
SELECT * 
FROM TABLE(TBL_FUNC(CURSOR(SELECT EMP_OT(EMPNO,...) FROM EMP)));
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105335
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Павел Воронцов,

какой тайный смысл цикла LOOP?

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105346
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL
Если в пакете - выдает ошибку.

Мудрить надо меньше.
Код: 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.
create table dropme_t as select rownum rn, sysdate dt from dual connect by level < 5;

Table created

CREATE OR REPLACE PACKAGE dropme_TYPE_DEF_PKG
AS
  cursor c is select * from dropme_t;
  TYPE EMP_RCT IS REF CURSOR RETURN c%ROWTYPE;
  TYPE EMP_NTT IS TABLE OF c%ROWTYPE;
  FUNCTION TBL_FUNC (CV_IN IN EMP_RCT) RETURN EMP_NTT PIPELINED;
END;
/

Package created

CREATE OR REPLACE PACKAGE body dropme_TYPE_DEF_PKG as
-- TABLE FUNCTION
	FUNCTION TBL_FUNC (CV_IN IN EMP_RCT) RETURN EMP_NTT PIPELINED
	IS
		L_ROW CV_IN%ROWTYPE;
	BEGIN
		LOOP
			FETCH CV_IN INTO L_ROW;
			EXIT WHEN CV_IN%NOTFOUND;
			pipe row (l_row);
		END LOOP;
		CLOSE CV_IN;
		RETURN;
	exception when others then
		CLOSE CV_IN;
		raise;
	END;
END;
/

Package body created

SELECT *
  FROM dropme_TYPE_DEF_PKG.TBL_FUNC(CURSOR(SELECT * FROM dropme_t));

        RN DT
---------- -----------
         1 2021-10-19
         2 2021-10-19
         3 2021-10-19
         4 2021-10-19

SQL> 
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105347
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

у ArchiSQL ф-ция не PIPELINED и не в пакете

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105350
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax
ф-ция не PIPELINED и не в пакете

ЕМНИП, автоматическая генерация типов уровня схемы на основе пакетных типов есть только у pipelined.
Впрочем, на сегодня не знаю ни одной причины делать табличную не-pipelined функцию, предназначенную для использования в качестве источника данных для sql-запроса.

А что не в пакете - это не важно:
Код: 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.
CREATE OR REPLACE  FUNCTION dropme_TBL_FUNC (CV_IN IN dropme_TYPE_DEF_PKG.EMP_RCT) RETURN dropme_TYPE_DEF_PKG.EMP_NTT PIPELINED
  IS
    L_ROW CV_IN%ROWTYPE;
  BEGIN
    LOOP
      FETCH CV_IN INTO L_ROW;
      EXIT WHEN CV_IN%NOTFOUND;
      pipe row (l_row);
    END LOOP;
    CLOSE CV_IN;
    RETURN;
  exception when others then
    CLOSE CV_IN;
    raise;
END;
/

Function created

SELECT *
  FROM dropme_TBL_FUNC(CURSOR(SELECT * FROM dropme_t));

        RN DT
---------- -----------
         1 2021-10-19
         2 2021-10-19
         3 2021-10-19
         4 2021-10-19

SQL> 
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105355
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Павел Воронцов

А если так?


Все было бы хорошо, если бы не:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    TYPE EMP_RCT IS REF CURSOR RETURN EMP_OT;
  4  END;
  5  /

Warning: Package created with compilation errors.

SQL> show err
Errors for PACKAGE TYPE_DEF_PKG:

LINE/COL ERROR
-------- -----------------------------------------------------------------
3/3      PL/SQL: Declaration ignored
3/19     PLS-00362: invalid cursor return type; 'EMP_OT' must be a record
         type

SQL>



А если объявлять RETURN EMP%ROWTYPE; (как у меня) будет несоответствие типов на этапе FETCH CV_IN BULK COLLECT INTO RETVAL;

andrey_anonymous, спасибо, посмотрю Ваше решение
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105364
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL
посмотрю Ваше решение

Определние типов для pipelined через курсор очень удобно, но в 18с и 19с oracle накосячил с генерацией типов - генерируются атрибуты с идентификаторами "ATTR_1", "ATTR_2", ... "ATTR_N" вместо определенных курсором.
Doc ID 2517404.1
Есть патч и два workarounds, но они описаны в ноте и потому я не могу тут об этом написать, не нарушая правил форума.

..определять тип курсора через table_name%rowtype не очень удачная практика, как по мне.
Привязка к конкретной таблице остаётся жесткой.
Проще прямо внутри pipelined цикл по конкретной таблице зарядить, если не функция предполагает некоторой доли универсальности.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105424
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax,

Недоглядел. Не вели казнить, отец родной!
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105428
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL

Все было бы хорошо, если бы не:

Говорю же - давно я Оркалом не махал. Забыл уже нюансы, от пальцев не отскакивает.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105438
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous,

andrey_anonymous

Определние типов для pipelined через курсор очень удобно


andrey_anonymous

определять тип курсора через table_name%rowtype не очень удачная практика, как по мне.
Привязка к конкретной таблице остаётся жесткой.


Да, мне Ваше решение понравилось. Привязка к таблице только в одном месте в определении курсора. И для pipelined функции fetch идет на уровне строки, а не отдельно по полям.

Насчет использования pipeline вместо потоковой - понял, спасибо.

Есть еще один вопрос - в книге Фейштейна сказано:
"Prior to Oracle Database 12c, table functions could return only nested tables and VARRAYs. From 12.1, you can also define table fuctions that return an integer-indexed associative array whose type is defined in a package ".

По всей видимости речь идет о потоковой табличной функции, т.к. для pipeline:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT * FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE INDEX BY PLS_INTEGER;
  6    FUNCTION TBL_FUNC (CV_IN IN EMP_RCT) RETURN EMP_AAT PIPELINED;
  7  END;
  8  /

Warning: Package created with compilation errors.

SQL> show err
Errors for PACKAGE TYPE_DEF_PKG:

LINE/COL ERROR
-------- -----------------------------------------------------------------
6/12     PLS-00630: pipelined functions must have a supported collection
         return type



Сначала хочу сделать пример с потоковой табличной функцией для nested table, потом уже пробовать для associative array.

То есть мне нужно сделать потоковую табличную функцию с возвращаемой коллекцией типа nested type, определенной в пакете.
И тут как ни пробую получаю invalid datatype.

Пример кода:
Код: 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.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT * FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    --TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE INDEX BY PLS_INTEGER;
  6    TYPE EMP_NTT IS TABLE OF EMP_CUR%ROWTYPE;
  7    FUNCTION TBL_FUNC (CV_IN IN EMP_RCT) RETURN EMP_NTT/*EMP_AAT*/;
  8  END;
  9  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY TYPE_DEF_PKG AS
  2    FUNCTION TBL_FUNC (CV_IN IN EMP_RCT) RETURN EMP_NTT/*EMP_AAT*/
  3    IS
  4      RETVAL EMP_NTT/*EMP_AAT*/;
  5    BEGIN
  6      FETCH CV_IN BULK COLLECT INTO RETVAL;
  7      CLOSE CV_IN;
  8      RETURN RETVAL;
  9    END;
 10  END;
 11  /

Package body created.

SQL> SELECT *
  2  FROM TABLE(TYPE_DEF_PKG.TBL_FUNC(CURSOR(SELECT * FROM EMP)));
FROM TABLE(TYPE_DEF_PKG.TBL_FUNC(CURSOR(SELECT * FROM EMP)))
           *
ERROR at line 2:
ORA-00902: invalid datatype



Пробовал и с созданием объектного типа на уровне схемы, все равно когда коллекция объявлена на уровне пакета, ORA-00902: invalid datatype
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105441
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL,

andrey_anonymous

ЕМНИП, автоматическая генерация типов уровня схемы на основе пакетных типов есть только у pipelined.


.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105454
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL
Сначала хочу сделать пример с потоковой табличной функцией для nested table, потом уже пробовать для associative array.

Потоковая = PIPELINED.
Вы же упорно делаете просто табличную.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105456
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

так в примере выше создаются типы на уровне пакета, но все равно не работает.

А когда я создавал тип объекта на уровне схемы, все остальные типы были объявлены на уровне пакета. По сути своей я сделал тоже самое что в первом стартовом сообщении для рабочей версии, только коллекцию запихнул в пакет (а объектный тип оставил на уровне схемы) - и тоже самое сообщение ORA-00902: invalid datatype

Очень хочется проверить то о чем писал Фейштейн :)
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105457
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
ArchiSQL
Сначала хочу сделать пример с потоковой табличной функцией для nested table, потом уже пробовать для associative array.

Потоковая = PIPELINED.
Вы же упорно делаете просто табличную.


В соответствии с книгой Фейштейна (на русском языке), потоковая - обычная; конвеерная - pipelined

С pipelined (конвеерной) я привел вышел пример, для которого тип коллекции ассоциативный массив не поддерживается с этим типом табличной функции. Поэтому вариант только один - создать потоковую (обычную) табличную функцию
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105459
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL
так в примере выше создаются типы на уровне пакета, но все равно не работает.

Вероятно, Вы несколько поторопились переходить к Ферштейну.
Начните с database concepts, где сможете узнать, что oracle rdbms - в некотором смысле чудовище Франкенштейна, содержащее независимые машины SQL и PL/SQL, каждая - со своими типами данных и механизмами.
Потому определение типа в пакете - это тип PL/SQL, а определение типа в схеме - это тип SQL-машины.
И они разные.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105461
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andrey_anonymous
ArchiSQL
так в примере выше создаются типы на уровне пакета, но все равно не работает.

Вероятно, Вы несколько поторопились переходить к Ферштейну.
Начните с database concepts, где сможете узнать, что oracle rdbms - в некотором смысле чудовище Франкенштейна, содержащее независимые машины SQL и PL/SQL, каждая - со своими типами данных и механизмами.
Потому определение типа в пакете - это тип PL/SQL, а определение типа в схеме - это тип SQL-машины.
И они разные.


Спасибо за совет, концепты читал, все что Вы написали мне хорошо известно)
Я лишь хочу попробовать сделать так, как написано в книге - табличная функция возвращающая коллекцию типа ассоциативный массив, определенную в пакете.
Реализацию с коллекцией типа nested table на уровне схемы я привел в первом сообщении. Далее привел пример, что написанное в книге нельзя реализовать с pipelined функцией, поэтому нужно брать обычные потоковую функцию. И здесь да, выдает сообщение о несоответствие типов. Но это вовсе не означает, что я не знаю что такое SQL; PL/SQL ядро и то что типы данных используемые в БД и поддерживаемые SQL ядром отличаются от типов данных поддерживаемых PL/SQL ядром.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105635
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ArchiSQL

Есть еще один вопрос - в книге Фейштейна сказано:
"Prior to Oracle Database 12c, table functions could return only nested tables and VARRAYs. From 12.1, you can also define table fuctions that return an integer-indexed associative array whose type is defined in a package ".


Версия 12.1
Создаю обычную потоковую табличную функцию возвращающую коллекцию типа ассоциативный массив индексируемый по типу varchar2 (считаем что ename уникальны) уровня пакета. Получаем ошибку на этапе компиляции sql запроса.
Код: 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.
60.
61.
62.
63.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT EMPNO, ENAME FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE INDEX BY VARCHAR2(100);
  6    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT;
  7  END;
  8  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY TYPE_DEF_PKG AS
  2    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT
  3     IS
  4       RETVAL EMP_AAT;
  5       REC CV_IN%ROWTYPE;
  6    BEGIN
  7       --FETCH CV_IN BULK COLLECT INTO RETVAL;
  8         LOOP
  9            FETCH CV_IN INTO REC;
 10            EXIT WHEN CV_IN%NOTFOUND;
 11            RETVAL(REC.ENAME).EMPNO := REC.EMPNO;
 12            RETVAL(REC.ENAME).ENAME := REC.ENAME;
 13         END LOOP;
 14       CLOSE CV_IN;
 15       RETURN RETVAL;
 16    END;
 17  END;
 18  /

Package body created.

SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4    L_IDX VARCHAR2(100);
  5  BEGIN
  6    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  7    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
  8
  9    L_IDX := L_AA_VAR.FIRST;
 10    LOOP
 11      EXIT WHEN L_IDX IS NULL;
 12      DBMS_OUTPUT.PUT_LINE(L_AA_VAR(L_IDX).EMPNO || ' - ' || L_AA_VAR(L_IDX).ENAME);
 13      L_IDX := L_AA_VAR.NEXT(L_IDX);
 14    END LOOP;
 15
 16    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 17      LOOP
 18        NULL;
 19        --DBMS_OUTPUT.PUT_LINE(REC.EMPNO || ' - ' || REC.ENAME);
 20      END LOOP;
 21  END;
 22  /
  FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
                                  *
ERROR at line 16:
ORA-06550: line 16, column 35:
PLS-00382: expression is of wrong type
ORA-06550: line 16, column 29:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 16, column 15:
PL/SQL: SQL Statement ignored



Теперь создаю обычную потоковую табличную функцию возвращающую коллекцию типа ассоциативный массив индексируемый по типу pls_integer уровня пакета. Здесь все компилируется успешно как и написано у Фейштейна.
Код: 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.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT EMPNO, ENAME FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE INDEX BY PLS_INTEGER;
  6    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT;
  7  END;
  8  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY TYPE_DEF_PKG AS
  2    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT
  3     IS
  4       RETVAL EMP_AAT;
  5       REC CV_IN%ROWTYPE;
  6    BEGIN
  7       --FETCH CV_IN BULK COLLECT INTO RETVAL;
  8         LOOP
  9            FETCH CV_IN INTO REC;
 10            EXIT WHEN CV_IN%NOTFOUND;
 11            RETVAL(REC.EMPNO).EMPNO := REC.EMPNO;
 12            RETVAL(REC.EMPNO).ENAME := REC.ENAME;
 13         END LOOP;
 14       CLOSE CV_IN;
 15       RETURN RETVAL;
 16    END;
 17  END;
 18  /

Package body created.

SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4    L_IDX PLS_INTEGER;
  5  BEGIN
  6    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  7    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
  8
  9    L_IDX := L_AA_VAR.FIRST;
 10    LOOP
 11      EXIT WHEN L_IDX IS NULL;
 12      DBMS_OUTPUT.PUT_LINE(L_AA_VAR(L_IDX).EMPNO || ' - ' || L_AA_VAR(L_IDX).ENAME);
 13      L_IDX := L_AA_VAR.NEXT(L_IDX);
 14    END LOOP;
 15
 16    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 17      LOOP
 18        NULL;
 19        --DBMS_OUTPUT.PUT_LINE(REC.EMPNO);
 20      END LOOP;
 21  END;
 22  /

PL/SQL procedure successfully completed.



Сейчас остаются неясными 3 вопроса:

1. SQL компилятор выполняет запрос SELECT * FROM TABLE(L_AA_VAR), где L_AA_VAR - ассоциативный массив индексируемый по pls_integer. Почему тогда поле таблицы может иметь тип коллекции только nested table или varray, но не ассоциативный массив.
2. Если для рабочей версии с индексированием по pls_integer я опускаю переменную L_AA_VAR и пишу FOR REC IN (SELECT * FROM TABLE(TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA))), то получаю ошибку
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
SQL> DECLARE
  2    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  3  BEGIN
  4    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  5
  6    FOR REC IN (SELECT * FROM TABLE(TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA)))
  7      LOOP
  8        NULL;
  9        --DBMS_OUTPUT.PUT_LINE(REC.EMPNO);
 10      END LOOP;
 11  END;
 12  /
  FOR REC IN (SELECT * FROM TABLE(TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA)))
                                               *
ERROR at line 6:
ORA-06550: line 6, column 48:
PLS-00382: expression is of wrong type
ORA-06550: line 6, column 29:
PL/SQL: ORA-22905: cannot access rows from a non-nested table item
ORA-06550: line 6, column 15:
PL/SQL: SQL Statement ignored



Если через L_AA_VAR, ошибки нет
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SQL> DECLARE
  2    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  3    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  4  BEGIN
  5    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  6    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
  7
  8    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
  9      LOOP
 10        NULL;
 11        --DBMS_OUTPUT.PUT_LINE(REC.EMPNO);
 12      END LOOP;
 13  END;
 14  /

PL/SQL procedure successfully completed.


3. В цикле
Код: plsql
1.
2.
3.
4.
5.
FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 LOOP
   NULL;
   --DBMS_OUTPUT.PUT_LINE(REC.EMPNO || ' - ' || REC.ENAME);
END LOOP; 


если я раскомментариваю DBMS_OUTPUT, то выдает ошибку, почему, непонятно.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105640
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL

[/src]
3. В цикле
Код: plsql
1.
2.
3.
4.
5.
FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 LOOP
   NULL;
   --DBMS_OUTPUT.PUT_LINE(REC.EMPNO || ' - ' || REC.ENAME);
END LOOP; 


если я раскомментариваю DBMS_OUTPUT, то выдает ошибку, почему, непонятно.


как вариант, оптимизатор убрал Ваш пустой цикл for rec

зы
c пустым циклом желательно не тестировать

вместо DBMS_OUTPUT, можете вставить напр i:=i+1; шоб не пустой был
+вывод і после цикла

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105739
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
[quot Stax#22385978]
ArchiSQL

как вариант, оптимизатор убрал Ваш пустой цикл for rec

зы
c пустым циклом желательно не тестировать

вместо DBMS_OUTPUT, можете вставить напр i:=i+1; шоб не пустой был
+вывод і после цикла

.....
stax


Да, согласен, это я излишне пообрезал для форума :) Вернул обратно)

То что цикл в строках 11-15 выполняется - это понятно, PL/SQL ядро заполняет ассоциативный массив L_AA_VAR вызовом функции TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA).
В цикле в строках 18-22 источник данных SQL запроса - ассоциативный массив, преобразованный оператором table(). И он выполняется SQL ядром, и поддерживается. Хотя в моем понимании ассоциативный массив не может быть типом данных БД и не может быть отработан SQL ядром, но видимо я ошибаюсь.

Кстати, по поводу моего 2 вопроса:
http://www.dba-oracle.com/t_plsql_associative_array_example.htm
"Note: The function with its return type as an associative array cannot be directly used in the TABLE function and it has to be assigned to a local variable for it to use the TABLE function as shown in the below example."
Почему - не объясняется.

И там же идет вывод через DBMS_OUTPUT.PUT_LINE (мой 3 вопрос).
Если я расскомментирую вывод, получаю ошибку:
ERROR at line 21:
ORA-06550: line 21, column 32:
PLS-00302: component 'EMPNO' must be declared
ORA-06550: line 21, column 7:
PL/SQL: Statement ignored


Код: 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.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT EMPNO, ENAME FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE INDEX BY PLS_INTEGER;
  6    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT;
  7  END;
  8  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY TYPE_DEF_PKG AS
  2    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT
  3    IS
  4      RETVAL EMP_AAT;
  5      REC CV_IN%ROWTYPE;
  6    BEGIN
  7      --FETCH CV_IN BULK COLLECT INTO RETVAL;
  8      LOOP
  9          FETCH CV_IN INTO REC;
 10          EXIT WHEN CV_IN%NOTFOUND;
 11          RETVAL(REC.EMPNO).EMPNO := REC.EMPNO;
 12          RETVAL(REC.EMPNO).ENAME := REC.ENAME;
 13      END LOOP;
 14      CLOSE CV_IN;
 15      RETURN RETVAL;
 16    END;
 17  END;
 18  /

Package body created.

SQL> SET SERVEROUTPUT ON;
SQL> /

Package body created.

SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4    L_IDX PLS_INTEGER;
  5    L_CNT PLS_INTEGER := 0;
  6  BEGIN
  7    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  8    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
  9
 10    L_IDX := L_AA_VAR.FIRST;
 11    LOOP
 12      EXIT WHEN L_IDX IS NULL;
 13      DBMS_OUTPUT.PUT_LINE(L_AA_VAR(L_IDX).EMPNO || ' - ' || L_AA_VAR(L_IDX).ENAME);
 14      L_IDX := L_AA_VAR.NEXT(L_IDX);
 15    END LOOP;
 16
 17    DBMS_OUTPUT.PUT_LINE('L_CNT BEFORE LOOP: ' || L_CNT);
 18    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 19      LOOP
 20        L_CNT := L_CNT + 1;
 21         --DBMS_OUTPUT.PUT_LINE(REC.EMPNO);
 22      END LOOP;
 23    DBMS_OUTPUT.PUT_LINE('L_CNT AFTER LOOP: ' || L_CNT);
 24  END;
 25  /
7369 - SMITH
7499 - ALLEN
7521 - WARD
7566 - JONES
7654 - MARTIN
7698 - BLAKE
7782 - CLARK
7788 - SCOTT
7839 - KING
7844 - TURNER
7876 - ADAMS
7900 - JAMES
7902 - FORD
7934 - MILLER
L_CNT BEFORE LOOP: 0
L_CNT AFTER LOOP: 14

PL/SQL procedure successfully completed.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105742
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL

Почему - не объясняется.


22385407

оракля втихаря создает (создавал) SQL тип, аля SYS_PLSQL_123456_78_1 ,
возможно Вы нарвались на баг,
посмотрите шо возвращает ("структуру") SELECT * FROM TABLE(L_AA_VAR)

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105751
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax
ArchiSQL

Почему - не объясняется.


22385407

оракля втихаря создает (создавал) SQL тип, аля SYS_PLSQL_123456_78_1 ,
возможно Вы нарвались на баг,
посмотрите шо возвращает ("структуру") SELECT * FROM TABLE(L_AA_VAR)

.....
stax


Sql запрос не в pl/sql блоке не отрабатывает. А как еще посмотреть структуру - пока нет идей.

Код: plsql
1.
2.
3.
4.
5.
6.
SQL> SELECT *
  2  FROM TABLE(TYPE_DEF_PKG.TBL_FUNC_AA(CURSOR(SELECT EMPNO, ENAME FROM EMP)));
FROM TABLE(TYPE_DEF_PKG.TBL_FUNC_AA(CURSOR(SELECT EMPNO, ENAME FROM EMP)))
           *
ERROR at line 2:
ORA-00902: invalid datatype



Но это не отменяется того факта, что sql ядро обрабатывает запрос SELECT * FROM TABLE(L_AA_VAR) внутри анонимного pl/sql блока. А это возможно в 3 случаях:
1. Использование существующих типов коллекций odcinumberlist, odcivarchar2list
2. Явное создание типа коллекции на уровне схемы create type
3. Пакетное определение типа коллекции (мой случай), в котором оракл автоматически создает внутренний тип данных на уровне схемы.

Кстати, мой пример кода в прошлом сообщении показывает, что автоматическая генерация типов уровня схемы произошла для обычной табличной функции, не pipelined.
andrey_anonymous

ЕМНИП, автоматическая генерация типов уровня схемы на основе пакетных типов есть только у pipelined.


Возможно я где-то ошибаюсь, было бы интересно услышать комментарии andrey_anonymous на этот счет
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105754
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL

Sql запрос не в pl/sql блоке не отрабатывает. А как еще посмотреть структуру - пока нет идей.

dbms_sql

ps
XML

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105786
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax
ArchiSQL

Sql запрос не в pl/sql блоке не отрабатывает. А как еще посмотреть структуру - пока нет идей.

dbms_sql


А что для парсинга передавать? Коллекция L_AA_VAR генерирует свой внутренний тип на уровне схемы, какое у него название и где его найти - под sys наверное в словаре данных должен быть

То есть код ниже не пройдет если передавать влоб SELECT * FROM TABLE(L_AA_VAR)

Код: 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.
60.
SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4    L_IDX PLS_INTEGER;
  5    L_CNT PLS_INTEGER := 0;
  6
  7    CUR PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;
  8    COLS DBMS_SQL.DESC_TAB;
  9    NCOLS PLS_INTEGER;
 10  BEGIN
 11    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
 12    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
 13
 14    L_IDX := L_AA_VAR.FIRST;
 15    LOOP
 16      EXIT WHEN L_IDX IS NULL;
 17      DBMS_OUTPUT.PUT_LINE(L_AA_VAR(L_IDX).EMPNO || ' - ' || L_AA_VAR(L_IDX).ENAME);
 18      L_IDX := L_AA_VAR.NEXT(L_IDX);
 19    END LOOP;
 20
 21    DBMS_OUTPUT.PUT_LINE('L_CNT BEFORE LOOP: ' || L_CNT);
 22    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 23      LOOP
 24      L_CNT := L_CNT + 1;
 25        --DBMS_OUTPUT.PUT_LINE(REC.EMPNO);
 26      END LOOP;
 27    DBMS_OUTPUT.PUT_LINE('L_CNT AFTER LOOP: ' || L_CNT);
 28
 29    DBMS_SQL.PARSE
 30              (CUR, 'SELECT * FROM TABLE(L_AA_VAR)', DBMS_SQL.NATIVE);
 31    DBMS_SQL.DESCRIBE_COLUMNS(CUR, NCOLS, COLS);
 32    FOR COLIND IN 1 .. NCOLS
 33      LOOP
 34        DBMS_OUTPUT.PUT_LINE(COLS(COLIND).COL_NAME);
 35      END LOOP;
 36    DBMS_SQL.CLOSE_CURSOR(CUR);
 37  END;
 38  /
7369 - SMITH
7499 - ALLEN
7521 - WARD
7566 - JONES
7654 - MARTIN
7698 - BLAKE
7782 - CLARK
7788 - SCOTT
7839 - KING
7844 - TURNER
7876 - ADAMS
7900 - JAMES
7902 - FORD
7934 - MILLER
L_CNT BEFORE LOOP: 0
L_CNT AFTER LOOP: 14
DECLARE
*
ERROR at line 1:
ORA-00904: "L_AA_VAR": invalid identifier
ORA-06512: at "SYS.DBMS_SQL", line 1120
ORA-06512: at line 29
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105792
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL

уровне схемы, какое у него название и где его найти - под sys наверное в словаре данных должен быть



https://community.oracle.com/tech/developers/discussion/2286500/object-of-type-sys-plsql-how-to-determine-association-to-pkg-or-prc

на работе я от оракла (почти) отключен, многое пробовать не могу

наскоко помню, в v$sql видно название типа, но могу ошибатся, давно было

зы
Узнать имя пакета, в котором содержится тип record

.....
stax
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105817
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В прошлом сообщении накосячил с dbms_sql.

Вот правильный запрос для определения наименований полей:

Код: 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.
SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT;
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4
  5    CUR PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;
  6    COLS DBMS_SQL.DESC_TAB;
  7    NCOLS PLS_INTEGER;
  8
  9    CUR_EMP SYS_REFCURSOR;
 10  BEGIN
 11    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
 12    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
 13
 14    OPEN CUR_EMP FOR SELECT * FROM TABLE(L_AA_VAR);
 15    CUR := DBMS_SQL.TO_CURSOR_NUMBER(RC => CUR_EMP);
 16
 17    DBMS_SQL.DESCRIBE_COLUMNS(CUR, NCOLS, COLS);
 18    FOR COLIND IN 1 .. NCOLS
 19      LOOP
 20        DBMS_OUTPUT.PUT_LINE(COLS(COLIND).COL_NAME);
 21      END LOOP;
 22    DBMS_SQL.CLOSE_CURSOR(CUR);
 23
 24  END;
 25  /
ATTR_1
ATTR_2

PL/SQL procedure successfully completed.



То есть это то, о чем писал выше andrey_anonymous, только и для 12.1 актуально.

andrey_anonymous
ArchiSQL
посмотрю Ваше решение

Определние типов для pipelined через курсор очень удобно, но в 18с и 19с oracle накосячил с генерацией типов - генерируются атрибуты с идентификаторами "ATTR_1", "ATTR_2", ... "ATTR_N" вместо определенных курсором.
Doc ID 2517404.1
Есть патч и два workarounds, но они описаны в ноте и потому я не могу тут об этом написать, не нарушая правил форума.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105918
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Можно резюмировать следующее:
  • 1. Коллекции типа nested table и varray могут быть объявлены на уровне схемы (поэтому могут быть как типами данных столбца таблицы, так и использоваться в SQL) и/или в спецификации пакета. В последнем случае при использовании в SQL запросах (коллекция как результирующее значение табличной функции (потоковой и/или pipelined) преобразованное оператором table в источник данных для запроса) происходит автоматическая генерация типов (записываются в словари данных) на уровне схемы.
Здесь кстати возник вопрос - в примере andrey_anonymous'а для pipelined table function указано, что эта функция возвращает тип nested table, объявленный в спецификации пакета. При этом генерирование данных этого типа не происходит (фетчится запись из курсора и подается на выход), Oracle все равно этот тип данных преобразует на уровень схемы?
    2. Обьявить тип index by коллекции на уровне схемы нельзя, поэтому для его использования в подпрограммах PL/SQL (в том числе, как результирующее значение табличной функции) этот тип должен быть объявлен в спецификация пакета.
3. Табличная функция может быть потоковой и конвеерной (pipelined). 3.1 В pipelined table function не допускается использование index by коллекции. 3.2 Для потоковой table function допускается использования index by коллекции. 3.2.1 Если такая коллекция индексирована по varchar2, то SQL ядро выдает ошибку на этапе sql запроса к табличной функции. 3.2.2 Индексирование должно идти по целочисленным значениям, при этом Oracle автоматически создает внутренний тип данных на уровне схемы для этой index by коллекции. Есть нюанс с идентификаторами атрибутов - назначаются "ATTR_1", "ATTR_2", ... вместо тех что определены в курсоре.
Код: 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.

SQL> CREATE OR REPLACE PACKAGE TYPE_DEF_PKG
  2  AS
  3    CURSOR EMP_CUR IS SELECT EMPNO, ENAME FROM EMP;
  4    TYPE EMP_RCT IS REF CURSOR RETURN EMP_CUR%ROWTYPE;
  5    TYPE EMP_AAT IS TABLE OF EMP_CUR%ROWTYPE;
  6    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT;
  7  END;
  8  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY TYPE_DEF_PKG AS
  2    FUNCTION TBL_FUNC_AA (CV_IN IN EMP_RCT) RETURN EMP_AAT
  3     IS
  4       RETVAL EMP_AAT := EMP_AAT();
  5       REC CV_IN%ROWTYPE;
  6    BEGIN
  7       FETCH CV_IN BULK COLLECT INTO RETVAL;
  8       CLOSE CV_IN;
  9       RETURN RETVAL;
 10    END;
 11  END;
 12  /

Package body created.

SQL> DECLARE
  2    L_AA_VAR TYPE_DEF_PKG.EMP_AAT := TYPE_DEF_PKG.EMP_AAT();
  3    CUR_VAR_AA TYPE_DEF_PKG.EMP_RCT;
  4  BEGIN
  5    OPEN CUR_VAR_AA FOR SELECT EMPNO, ENAME FROM EMP;
  6    L_AA_VAR.EXTEND(14);
  7    L_AA_VAR := TYPE_DEF_PKG.TBL_FUNC_AA(CUR_VAR_AA);
  8
  9    FOR REC IN (SELECT * FROM TABLE(L_AA_VAR))
 10      LOOP
 11        NULL;
 12        DBMS_OUTPUT.PUT_LINE(REC.ATTR_1 || ' - ' || REC.ATTR_2);
 13      END LOOP;
 14  END;
 15  /
7839 - KING
7698 - BLAKE
7782 - CLARK
7566 - JONES
7788 - SCOTT
7902 - FORD
7369 - SMITH
7499 - ALLEN
7521 - WARD
7654 - MARTIN
7844 - TURNER
7876 - ADAMS
7900 - JAMES
7934 - MILLER

PL/SQL procedure successfully completed.
Покритикуйте, плиз, где что не так.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105949
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL,

как минимум, вот это
Код: plsql
1.
6    L_AA_VAR.EXTEND(14);


говорит о том, что вы плохо понимаете, что такое "присвоение значения переменной".

А вообще, игрушки подобного рода, обычно работают без явных багов (или "особенностей" реализации) в ограниченном числе ситуаций .
Не знаю, исправили ли в 20й версии все то, что наломали в 18й и 19й..
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105990
ArchiSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
booby
ArchiSQL,

как минимум, вот это
Код: plsql
1.
6    L_AA_VAR.EXTEND(14);


говорит о том, что вы плохо понимаете, что такое "присвоение значения переменной".


Ну началось, полетела душа в рай :) Очень ценное замечание )) Специально для Вас, можете 14 заменить на L_AA_VAR.COUNT. А так то я специально расширял коллекцию чтобы были пустые элементы и хотел кое-что попробовать, но я понимаю, это очень важный вопрос в контексте обсуждения табличных функций, не ускользнувший от Вашего орлиного взора, более того, потребовавший затрат Вашего времени на написание сообщения (тк ничего более полезного написано Вами не было :) )

booby

А вообще, игрушки подобного рода, обычно работают без явных багов (или "особенностей" реализации) в ограниченном числе ситуаций .
Не знаю, исправили ли в 20й версии все то, что наломали в 18й и 19й..


Одна вода, зачем писали, не понятно.... Но спасибо за Ваш пост, чувствуется та "пропасть" между Вашим сообщение и сообщением andrey_anonymous и Stax, где все четко, по делу.

Очень хотелось бы услышать комментарии последних, возможно я где-то был не прав, т.к. есть некоторые нестыковки с тем, что писал andrey_anonymous.
...
Рейтинг: 0 / 0
Пару вопросов по табличной функции
    #40105997
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArchiSQL
... Специально для Вас, можете 14 заменить на L_AA_VAR.COUNT.
....

я не могу.
И специально для нас не надо совершать бессмысленных действий.
...
Рейтинг: 0 / 0
30 сообщений из 30, показаны все 2 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пару вопросов по табличной функции
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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