2011-12-19 15 views
5

con sede fuera de how to return a dynamic result set in Oracle functionOracle SQL crear una función - confundir errores de compilación

que estoy tratando de hacer una función que devolverá una fila de varios cargos de varias tablas. Esto es lo que tengo hasta ahora:

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; 

Pero no importa lo que hago para que esto parezca ejemplos de funciones existentes, tanto aquí como en otros sitios, que no acepta cualquier cosa dentro del bloque BEGIN. El SQL dentro del bloque BEGIN funciona; Puedo ejecutar todos aquellos WITH AS SELECT etc. y me dará una fila como resultado con los conteos que estoy buscando. Pero esta función simplemente NO compilará. Dependiendo de dónde coloque un espacio o un punto y coma, los errores cambian. Errores actuales:

Error(7,3): PL/SQL: SQL Statement ignored 
Error(62,3): PL/SQL: ORA-00947: not enough values 

¿Ayuda? D:

Respuesta

6

Estás muy cerca, pero no seguiste la pregunta relacionada bastante con suficiente fidelidad. El motivo del mensaje not enough values es que solo tiene un valor en su cláusula INTO, pero Oracle espera que tenga ocho, ya que esa es la cantidad de expresiones (efectivamente) en su SELECT *. Necesita convertir esas ocho expresiones en un solo valor. Para hacer esto, debe cambiar su WITH ... SELECT * INTO out_rec ... en SELECT CAST(MULTISET(WITH ... SELECT * ...) AS result_table) INTO out_rec FROM dual o WITH ... SELECT CAST(MULTISET(SELECT * ...) AS result_table) INTO out_rec FROM dual, como prefiera.

Además, es necesario poner su cláusula FROM en el orden correcto, con LOC anterior ONE través EIGHT; el reparto se realiza en función de las posiciones relativas de las expresiones, no según los alias de campo. (Como alternativa, puede cambiar su SELECT * identificar explícitamente los campos, en el orden correcto, en lugar de confiar en el orden -clause FROM.)

+0

Heh, eso es lo que obtengo por usar algo que no entiendo. Perdón por molestarte. Esos problemas eran exactamente eso, funciona ahora. :) –

+0

No hay necesidad de disculparse. Me alegra que esté funcionando para ti. :-) – ruakh

4

@ respuesta de ruakh que implican CAST y MULTISET en realidad es más complicada de lo que debe ser . Es necesario utilizar el constructor por defecto para RESULT_ROW y utilizar BULK COLLECT con el fin de devolver una colección:

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

(obviamente, esta es una versión simplificada Como no tengo las tablas, que recurrió a la sustitución de dual. en su lugar.)

+0

+1. Curiosamente, la forma en que describes es, en realidad, más o menos cómo lo hago en mi propio código (¡incluida esta mañana!); la única razón por la que fui con 'CAST (MULTISET (...) AS ...)' es que el OP intentaba seguir un ejemplo que usaba ese enfoque. – ruakh

Cuestiones relacionadas