2012-05-17 11 views
11

Ho bisogno di creare una funzione che eseguirà una query e restituirà i risultati con il nome della tabella e il nome della colonna come arugmenti dati alla funzione. Al momento ho questo:Funzione query dinamica Postgres

CREATE OR REPLACE FUNCTION qa_scf(tname character varying, cname character varying) 
RETURNS SETOF INT AS 
$BODY$ 
BEGIN 
RETURN QUERY SELECT * FROM tname WHERE cname !='AK' AND cname!='CK'; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE 
COST 100 
ROWS 1000; 

Questo mi dà l'errore "Relation 'TNAME' des non esiste" quando viene eseguito. Sono nuovo nella funzione di creazione per Postgres, quindi qualsiasi aiuto è apprezzato. Mi sento come se il return int fosse sbagliato, ma non so cos'altro mettere per fare restituire tutte le colonne per le righe restituite. Grazie!

risposta

17

Non è possibile utilizzare una variabile al posto di un identificatore del genere. Hai bisogno di farlo con query dinamiche. Sarà simile a questa:

EXECUTE 'SELECT * FROM ' || quote_ident(tname) 
     || ' WHERE ' || quote_ident(cname) || ' NOT IN (''AK'',''CK'');' 
INTO result_var; 

Se si utilizza PostgreSQL 9.1 o superiore, è possibile utilizzare the format() function che rende la costruzione di questa stringa molto più facile.

+0

Cosa dovrei dichiarare come risultato? –

+1

Non interpolare mai i valori in istruzioni SQL dinamiche senza utilizzare la funzione quote_FOO() appropriata o si apre la porta agli attacchi di iniezione. – dbenhur

+0

Questo è un database interno. –

13

I nomi di tabelle e colonne non possono essere specificati come parametri o variabili senza costruire dinamicamente una stringa da eseguire come istruzione dinamica. Postgres ha un'ottima documentazione introduttiva su executing dynamic statements. È importante citare correttamente identificatori e letterali con quote_ident() o quote_literal(). La funzione format() aiuta a ripulire la costruzione di istruzioni sql dinamiche. Poiché dichiari la funzione per restituire SETOF INTEGER, devi selezionare il campo intero desiderato, non *.

CREATE OR REPLACE FUNCTION qa_scf(tname text, cname text) 
RETURNS SETOF INTEGER AS 
$BODY$ 
BEGIN 
    RETURN QUERY EXECUTE format(
    'SELECT the_integer_field FROM %I WHERE %I NOT IN (%L, %L)', 
            tname, cname, 'AK', 'CK' 
); 
END; 
$BODY$ 
LANGUAGE plpgsql; 
+0

Come faccio a restituire tutte le colonne? –

+0

È possibile 'SELEZIONARE *' e dichiarare 'RETURNS SETOF RECORD'. Quindi il consumatore deve capire la tupla record. http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions – dbenhur

+0

E come faccio a dargli l'elenco delle definizioni delle colonne? C'è un modo per tirare dinamicamente questo? –