Funzione di sanificazione
Quello che hai attualmente può essere semplificato/igienizzato in:
CREATE OR REPLACE FUNCTION func_a (username text = '', databaseobject text = '')
RETURNS ????
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ('SELECT * FROM %s v1 LEFT JOIN %I v2 USING (id)'
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
, databaseobject);
END
$func$;
Hai solo bisogno di ulteriori istanze di BEGIN ... END
nel corpo della funzione per avviare blocchi di codice separati con il proprio ambito, che è raramente necessario.
L'operatore di concatenazione SQL standard è ||
. +
è un'aggiunta "creativa" del tuo ex fornitore.
Non utilizzare identificatori di maiuscole e minuscole CaMeL a meno che non vengano virgolette. Meglio non usarli affatto Vedi:
- I nomi delle colonne di PostgreSQL fanno distinzione tra maiuscole e minuscole?
varchar(4000)
è inoltre adattato a una specifica limitazione di SQL Server. Non ha un significato specifico in Postgres. Usa solo varchar(4000)
se hai effettivamente bisogno di un limite di 4000 caratteri. Userei semplicemente text
- tranne per il fatto che non abbiamo bisogno di alcuna variabile per niente qui, dopo aver semplificato la funzione.
Se non hai utilizzato format()
, tuttavia, consulta il manuale qui.
Tipo di reso
Ora, per la tua vera domanda:il tipo restituito per una query dinamica può essere complicato poiché SQL richiede che venga dichiarato al più tardi al momento della chiamata. Se hai una tabella o una vista o un tipo composto nel tuo database che corrisponde già all'elenco delle definizioni delle colonne, puoi semplicemente usarlo:
CREATE FUNCTION foo()
RETURNS SETOF my_view AS
...
Altrimenti, scrivi l'elenco delle definizioni delle colonne senza con (il più semplice) RETURNS TABLE
:
CREATE FUNCTION foo()
RETURNS TABLE (col1 int, col2 text, ...) AS
...
Se stai scrivendo la riga mentre procedi, puoi restituire record anonimi:
CREATE FUNCTION foo()
RETURNS SETOF record AS
...
Ma poi devi fornire un elenco di definizioni di colonna con ogni chiamata, quindi non lo uso quasi mai.
Non userei SELECT *
iniziare con. Utilizza un elenco definitivo di colonne da restituire e dichiara il tuo tipo di reso di conseguenza:
CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
RETURNS TABLE(col1 int, col2 text, col3 date)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
format ($f$SELECT v1.col1, v1.col2, v2.col3
FROM %s v1 LEFT JOIN %I v2 USING (id)$f$
, CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END
, databaseobject);
END
$func$;
Per query completamente dinamiche, per cominciare, considera la creazione della query nel tuo client, invece di utilizzare una funzione.
Devi prima capire le basi:
- Refactoring di una funzione PL/pgSQL per restituire l'output di varie query SELECT
- PL/pgSQL nel manuale di Postgres
Poi ci sono opzioni più avanzate con tipi polimorfici, che ti permettono di passare il tipo restituito al momento della chiamata. Altro nell'ultimo capitolo di:
- Refactoring di una funzione PL/pgSQL per restituire l'output di varie query SELECT