ORA-00947 недостаточно значений с функцией, возвращающей таблицу рекордов - PullRequest
0 голосов
/ 05 июня 2019

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

Итак, я собираю следующее:

2 типа:

CREATE OR REPLACE TYPE PGM_ROW AS OBJECT
    (
        pID      NUMBER(10),
        pName    VARCHAR2(300)
    );

CREATE OR REPLACE TYPE PGM_TAB AS TABLE OF PGM_ROW;

1 функция:

CREATE OR REPLACE FUNCTION FLOGIN (USER_ID NUMBER) RETURN PGM_TAB
AS  
    SELECTED_PGM   PGM_TAB;
BEGIN
    FOR RESTRICTION
        IN (  SELECT (SELECT LISTAGG (ID_CHANNEL, ',')
                                 WITHIN GROUP (ORDER BY ID_CHANNEL)
                        FROM (SELECT DISTINCT CHA2.ID_CHANNEL
                                FROM CHANNELS_ACCESSES CHA2
                                     JOIN CHANNELS CH2
                                         ON CH2.ID = CHA2.ID_CHANNEL
                               WHERE     CHA2.ID_ACCESS = CMPA.ID_ACCESS
                                     AND CH2.ID_CHANNELS_GROUP = CG.ID))
                         AS channels,
                     (SELECT LISTAGG (ID_SUBGENRE, ',')
                                 WITHIN GROUP (ORDER BY ID_SUBGENRE)
                        FROM (SELECT DISTINCT SGA2.ID_SUBGENRE
                                FROM SUBGENRES_ACCESSES SGA2
                                     JOIN CHANNELS_ACCESSES CHA2
                                         ON CHA2.ID_ACCESS = SGA2.ID_ACCESS
                                     JOIN CHANNELS CH2
                                         ON CH2.ID = CHA2.ID_CHANNEL
                               WHERE     SGA2.ID_ACCESS = CMPA.ID_ACCESS
                                     AND CH2.ID_CHANNELS_GROUP = CG.ID))
                         AS subgenres,
                     CG.NAME,
                     A.BEGIN_DATE,
                     A.END_DATE,
                     CMP.PREVIEW_ACCESS
                FROM USERS U
                     JOIN COMPANIES_ACCESSES CMPA
                         ON U.ID_COMPANY = CMPA.ID_COMPANY
                     JOIN COMPANIES CMP ON CMP.ID = CMPA.ID_COMPANY
                     JOIN ACCESSES A ON A.ID = CMPA.ID_ACCESS
                     JOIN CHANNELS_ACCESSES CHA
                         ON CHA.ID_ACCESS = CMPA.ID_ACCESS
                     JOIN SUBGENRES_ACCESSES SGA
                         ON SGA.ID_ACCESS = CMPA.ID_ACCESS
                     JOIN CHANNELS CH ON CH.ID = CHA.ID_CHANNEL
                     JOIN CHANNELS_GROUPS CG ON CG.ID = CH.ID_CHANNELS_GROUP
               WHERE U.ID = USER_ID
            GROUP BY CG.NAME,
                     A.BEGIN_DATE,
                     A.END_DATE,
                     CMPA.ID_ACCESS,
                     CG.ID,
                     CMP.PREVIEW_ACCESS)
    LOOP
        SELECT PFT.ID_PROGRAM, PFT.LOCAL_TITLE
          BULK COLLECT INTO SELECTED_PGM
          FROM PROGRAMS_FT PFT
         WHERE     PFT.ID_CHANNEL IN
                       (    SELECT TO_NUMBER (
                                       REGEXP_SUBSTR (RESTRICTION.CHANNELS,
                                                      '[^,]+',
                                                      1,
                                                      ROWNUM))
                              FROM DUAL
                        CONNECT BY LEVEL <=
                                   TO_NUMBER (
                                       REGEXP_COUNT (RESTRICTION.CHANNELS,
                                                     '[^,]+')))
               AND PFT.ID_SUBGENRE IN
                       (    SELECT TO_NUMBER (
                                       REGEXP_SUBSTR (RESTRICTION.SUBGENRES,
                                                      '[^,]+',
                                                      1,
                                                      ROWNUM))
                              FROM DUAL
                        CONNECT BY LEVEL <=
                                   TO_NUMBER (
                                       REGEXP_COUNT (RESTRICTION.SUBGENRES,
                                                     '[^,]+')))
               AND (PFT.LAUNCH_DATE BETWEEN RESTRICTION.BEGIN_DATE
                                        AND RESTRICTION.END_DATE);
    END LOOP;
    RETURN SELECTED_PGM;
END FLOGIN;

Я ожидаю, что функция tu вернет таблицу с 2 столбцами, содержащими все записи из таблицы PROGRAMS_FT, которые включены в доступ пользователя.

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

1 Ответ

0 голосов
/ 05 июня 2019

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

...
    LOOP
        SELECT PGM_ROW(PFT.ID_PROGRAM, PFT.LOCAL_TITLE)
          BULK COLLECT INTO SELECTED_PGM
          FROM PROGRAMS_FT PFT
...

(Это бесполезная причуда PL / SQL, которая говорит «недостаточно значений», а не «слишком много значений»,как и следовало ожидать, когда вы пытаетесь соединить две вещи в одну, я уверен, что однажды я нашел достаточно убедительное объяснение / оправдание, но в настоящий момент мне это не удается ...)

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

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

...