ORA-00947 函数返回 table 条记录的值不足
ORA-00947 not enough values with function returning table of records
所以我正在尝试构建一个函数,该函数 return 包含某些客户订阅中的项目记录。
所以我一直在构建以下内容:
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 return a table 有 2 列,其中包含来自 table PROGRAMS_FT 的所有记录,这些记录包含在用户访问权限中。
出于某种原因,我收到编译警告 ORA-000947。
我对错误代码的理解是,当插入的值与接收值的对象的类型不匹配时会发生错误代码,我在这里看不出这是怎么回事。
您正在选择两个标量值并试图将它们放入一个对象中。这不会自动发生,您需要将它们转换为一个对象:
...
LOOP
SELECT PGM_ROW(PFT.ID_PROGRAM, PFT.LOCAL_TITLE)
BULK COLLECT INTO SELECTED_PGM
FROM PROGRAMS_FT PFT
...
(这是 PL/SQL 的一个毫无用处的怪癖,它说 'not enough values' 而不是 'too many values',正如您在尝试将两件事合二为一时可能期望的那样;我敢肯定有一次我想出了一个相当有说服力的 explanation/excuse 但它现在让我逃脱了......)
我不确定你的循环是否有意义。假设您的游标查询 returns 多行,每次围绕循环您 替换 SELECTED_PGM
集合的内容 - 您可能认为您正在追加它,但这不是它的工作原理。因此,您最终将返回仅基于循环的最后一次迭代的集合。
聚合然后拆分数据似乎也需要大量工作。你也许可以为那些使用集合;但您可能可以摆脱游标和循环,并将游标查询与内部查询结合起来,这样效率更高,并且允许您对所有组合数据执行单个 bulk-collect。
所以我正在尝试构建一个函数,该函数 return 包含某些客户订阅中的项目记录。
所以我一直在构建以下内容:
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 return a table 有 2 列,其中包含来自 table PROGRAMS_FT 的所有记录,这些记录包含在用户访问权限中。
出于某种原因,我收到编译警告 ORA-000947。 我对错误代码的理解是,当插入的值与接收值的对象的类型不匹配时会发生错误代码,我在这里看不出这是怎么回事。
您正在选择两个标量值并试图将它们放入一个对象中。这不会自动发生,您需要将它们转换为一个对象:
...
LOOP
SELECT PGM_ROW(PFT.ID_PROGRAM, PFT.LOCAL_TITLE)
BULK COLLECT INTO SELECTED_PGM
FROM PROGRAMS_FT PFT
...
(这是 PL/SQL 的一个毫无用处的怪癖,它说 'not enough values' 而不是 'too many values',正如您在尝试将两件事合二为一时可能期望的那样;我敢肯定有一次我想出了一个相当有说服力的 explanation/excuse 但它现在让我逃脱了......)
我不确定你的循环是否有意义。假设您的游标查询 returns 多行,每次围绕循环您 替换 SELECTED_PGM
集合的内容 - 您可能认为您正在追加它,但这不是它的工作原理。因此,您最终将返回仅基于循环的最后一次迭代的集合。
聚合然后拆分数据似乎也需要大量工作。你也许可以为那些使用集合;但您可能可以摆脱游标和循环,并将游标查询与内部查询结合起来,这样效率更高,并且允许您对所有组合数据执行单个 bulk-collect。