2011-12-19 12 views
5

base al largo di how to return a dynamic result set in Oracle functionOracle SQL creazione di una funzione - confondendo errori di compilazione

Sto cercando di fare una funzione che restituisce una riga con diversi conteggi da diverse tabelle. Ecco quello che ho finora:

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; 

Ma non importa quello che faccio per rendere questo sembrare esempi di funzioni esistenti, sia qui che su altri siti, non accetta nulla all'interno del blocco BEGIN. L'SQL all'interno del blocco BEGIN funziona; Posso eseguire tutti quelli CON COME SELEZIONA ecc. E mi darà una riga come risultato con i conteggi che sto cercando. Ma questa funzione NON verrà compilata. A seconda di dove metto uno spazio o un punto e virgola, gli errori cambiano. Errori attuali:

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

Aiuto? D:

risposta

6

Sei molto vicino, ma non hai seguito abbastanza fedelmente la domanda collegata . Il motivo per il messaggio not enough values è che hai un solo valore nella clausola INTO, ma Oracle si aspetta che tu ne abbia otto, poiché è quante espressioni sono (effettivamente) nel tuo SELECT *. Devi lanciare quelle otto espressioni in un unico valore. Per fare ciò, è necessario cambiare il o il WITH ... SELECT CAST(MULTISET(SELECT * ...) AS result_table) INTO out_rec FROM dual, come preferisci.

Inoltre, è necessario mettere la vostra clausola FROM nel giusto ordine, con LOC precedente ONE attraverso EIGHT; il cast viene eseguito in base alle posizioni relative delle espressioni, non in base agli alias di campo. (In alternativa, è possibile modificare la vostra SELECT * per identificare in modo esplicito i campi, nel giusto ordine, piuttosto che basarsi su ordine -clause FROM.)

+0

Heh, questo è quello che ottengo per l'utilizzo di qualcosa che non capisco. Mi dispiace disturbarla. Quei problemi erano esattamente ciò - funziona ora. :) –

+0

Non c'è bisogno di scusarsi. Sono felice che funzioni per te. :-) – ruakh

4

@ risposta di ruakh coinvolgono CAST e MULTISET in realtà è più complicata di quello che deve essere . È necessario utilizzare il costruttore predefinito per RESULT_ROW e di utilizzare BULK COLLECT al fine di restituire un insieme:

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

(ovviamente, questa è una versione semplificata Come io non ho le tabelle, ho fatto ricorso a sostituire dual. al loro posto.)

+0

+1. Stranamente, il modo in cui descrivi è in realtà più o meno come lo faccio nel mio codice (anche solo stamattina!); l'unica ragione per cui sono andato con 'CAST (MULTISET (...) AS ...)' è che l'OP stava cercando di seguire un esempio che usava quell'approccio. – ruakh

Problemi correlati