基于how to return a dynamic result set in Oracle function
我正在尝试创建一个函数,该函数将返回一行,其中包含来自多个表的多个计数。这是我到目前为止所做的:
CREATE OR REPLACE TYPE RESULT_ROW is OBJECT
(LOC_TABLE_ENTRY_KY VARCHAR2(50),
LOCATION_NAME VARCHAR2(50),
A_ASSIGN_CNT VARCHAR2(50),
B_ASSIGN_CNT VARCHAR2(50),
C_ASSIGN_CNT VARCHAR2(50),
D_ASSIGN_CNT VARCHAR2(50),
E_ASSIGN_CNT VARCHAR2(50),
F_ASSIGN_CNT VARCHAR2(50),
G_ASSIGN_CNT VARCHAR2(50),
H_ASSIGN_CNT VARCHAR2(50));
/
CREATE OR REPLACE TYPE RESULT_TABLE AS TABLE OF RESULT_ROW;
/
CREATE OR REPLACE FUNCTION LOCATION_RULE_LOOKUP(P_LOCATION_VAR IN NUMBER)
RETURN RESULT_TABLE
IS
OUT_REC RESULT_TABLE;
BEGIN
WITH LOC AS
(SELECT LOC_TABLE_ENTRY_KY,
LOCATION_NAME
FROM LOCATION_CODE
WHERE LOC_TABLE_ENTRY_KY = P_LOCATION_VAR
),
ONE AS
(SELECT COUNT(*) AS A_ASSIGN_CNT
FROM COLLECTOR_ASSIGNMENT
WHERE LOCATION_CODE = P_LOCATION_VAR
AND FUNCTION_STATE_CODE = ' '
OR FUNCTION_STATE_CODE = '***'
),
TWO AS
(SELECT COUNT(*) AS B_ASSIGN_CNT
FROM COMM_PLAN_ASSGN_RULE
WHERE LOCATION_CODE = P_LOCATION_VAR
),
THREE AS
(SELECT COUNT(*) AS C_ASSIGN_CNT
FROM INPUT_TRANS_ASGN
WHERE LOCATION_CODE = P_LOCATION_VAR
),
FOUR AS
(SELECT COUNT(*) AS D_ASSIGN_CNT
FROM RECALL_DAYS_ASSGN_RULE
WHERE LOCATION_CODE = P_LOCATION_VAR
),
FIVE AS
(SELECT COUNT(*) AS E_ASSIGN_CNT
FROM SCRIPT_VIEW_ASSIGNMENT
WHERE LOCATION_CODE = P_LOCATION_VAR
AND FUNCTION_STATE_CODE = ' '
OR FUNCTION_STATE_CODE = '***'
AND SCRIPT_TYPE = 'V'
),
SIX AS
(SELECT COUNT(*) AS F_ASSIGN_CNT
FROM SCRIPT_VIEW_ASSIGNMENT
WHERE LOCATION_CODE = P_LOCATION_VAR
AND FUNCTION_STATE_CODE = ' '
OR FUNCTION_STATE_CODE = '***'
AND SCRIPT_TYPE = 'D'
),
SEVEN AS
(SELECT COUNT(*) AS G_ASSIGN_CNT
FROM TSR_ASSGN_RULE
WHERE LOCATION_CODE = P_LOCATION_VAR
),
EIGHT AS
(SELECT COUNT(*) AS H_ASSIGN_CNT
FROM TRAN_STATE_ASSGN_RULE
WHERE LOCATION_CODE = P_LOCATION_VAR
)
SELECT * INTO OUT_REC
FROM ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, LOC;
RETURN OUT_REC;
END LOCATION_RULE_LOOKUP;
但是无论我做什么使它看起来像现有的函数示例,无论是在这里还是在其他站点上,它都不接受BEGIN块中的任何内容。 BEGIN块内的SQL有效;我可以运行所有那些WITH AS SELECT等,它会给我一行作为结果与我正在寻找的计数。但是这个函数不会编译。根据我放置空格或分号的位置,错误会发生变化。目前的错误:
Error(7,3): PL/SQL: SQL Statement ignored
Error(62,3): PL/SQL: ORA-00947: not enough values
帮助? d:
答案 0 :(得分:6)
你非常亲密,但你没有足够忠实地关注链接问题相当。 not enough values
消息的原因是您的INTO
子句中只有一个值,但Oracle期望您有八个,因为这是{{1}中有多少表达式(有效) }。您需要将这八个表达式转换为单个值。为此,您需要根据需要将SELECT *
更改为WITH ... SELECT * INTO out_rec ...
或SELECT CAST(MULTISET(WITH ... SELECT * ...) AS result_table) INTO out_rec FROM dual
。
此外,您需要按照正确的顺序放置WITH ... SELECT CAST(MULTISET(SELECT * ...) AS result_table) INTO out_rec FROM dual
条款,FROM
前LOC
到ONE
;根据表达式的相对位置执行强制转换, not 基于字段别名。 (或者,您可以更改EIGHT
以按正确的顺序明确标识字段,而不是依赖SELECT *
- 子句顺序。)
答案 1 :(得分:4)
@ ruakh涉及CAST
和MULTISET
的答案实际上比它需要的更复杂。您需要使用RESULT_ROW
的默认构造函数并使用BULK COLLECT
才能返回集合:
CREATE OR REPLACE TYPE result_row IS OBJECT
(loc_table_entry_ky VARCHAR2(50),
location_name VARCHAR2(50),
a_assign_cnt VARCHAR2(50),
b_assign_cnt VARCHAR2(50),
c_assign_cnt VARCHAR2(50),
d_assign_cnt VARCHAR2(50),
e_assign_cnt VARCHAR2(50),
f_assign_cnt VARCHAR2(50),
g_assign_cnt VARCHAR2(50),
h_assign_cnt VARCHAR2(50));
/
CREATE OR REPLACE TYPE result_table AS TABLE OF result_row;
/
CREATE OR REPLACE FUNCTION location_rule_lookup(p_location_var IN NUMBER)
RETURN result_table IS
out_rec result_table;
BEGIN
WITH loc AS (SELECT 'blarg' AS loc_table_entry_ky, 'foo' AS location_name FROM DUAL),
one AS (SELECT COUNT( * ) AS a_assign_cnt FROM DUAL),
two AS (SELECT COUNT( * ) AS b_assign_cnt FROM DUAL),
three AS (SELECT COUNT( * ) AS c_assign_cnt FROM DUAL),
four AS (SELECT COUNT( * ) AS d_assign_cnt FROM DUAL),
five AS (SELECT COUNT( * ) AS e_assign_cnt FROM DUAL),
six AS (SELECT COUNT( * ) AS f_assign_cnt FROM DUAL),
seven AS (SELECT COUNT( * ) AS g_assign_cnt FROM DUAL),
eight AS (SELECT COUNT( * ) AS h_assign_cnt FROM DUAL)
SELECT result_row(loc_table_entry_ky,
location_name,
a_assign_cnt,
b_assign_cnt,
c_assign_cnt,
d_assign_cnt,
e_assign_cnt,
f_assign_cnt,
g_assign_cnt,
h_assign_cnt)
BULK COLLECT INTO out_rec
FROM one,
two,
three,
four,
five,
six,
seven,
eight,
loc;
RETURN out_rec;
END location_rule_lookup;
/
(很明显,这是一个简化版本。由于我没有你的桌子,我使用dual
代替他们。)