È importante comprendere la natura principale di questi cinque diversi tipi di dati/simboli :
1. 'my_tbl'
Una stringa letterale di unknown
digita . Quando viene utilizzato in SQL (incorporato nel codice plpgsql o meno), viene forzato a un tipo derivato dal contesto . Se non è possibile determinare il tipo, potrebbe essere necessario un cast esplicito. Come:'my_tbl'::text
.
2. 'my_tbl'::text
La stessa stringa letterale cast per digitare text
. Può contenere il nome di una tabella, ma in realtà è solo testo.
3. 'my_tbl'::regclass
Un identificatore di oggetto (OID)
per una classe registrata . Viene visualizzato e può essere inserito come stringa che rappresenta un nome oggetto valido ('my_tbl'
). L'output è qualificato automaticamente dallo schema ('my_schema.my_tbl'
) e/o tra virgolette ('"mY_TbL"'
) se sarebbe ambiguo o altrimenti illegale. Può essere una normale tabella , sequenza , visualizza , vista materializzata , tipo composito ecc. Dettagli in questa risposta correlata:
4. my_tbl_var my_tbl
(abbreviazione di my_tbl_var my_tbl%ROWTYPE
)
Nel DECLARE
sezione di un blocco di codice plpgsql che è una dichiarazione di variabile con un noto tipo di riga
(noto anche come tipo composito). Il tipo deve essere registrato nella tabella di sistema pg_class
(come con una regclass
variabile). Non è l'OID dell'oggetto di riferimento, ma il suo tipo di riga effettivo. my_tbl_var
e my_tbl
sono entrambi identificatori qui e non può essere parametrizzato. Puoi anche trasmettere direttamente qualsiasi riga o record:(123, 'foo')::my_tbl
5. my_tbl_var record
Nel DECLARE
sezione di un blocco di codice plpgsql che è la dichiarazione di un anonimo record
. Fondamentalmente, un segnaposto per un tipo di riga ancora sconosciuto / con una struttura ancora non definita. Può essere utilizzato nella maggior parte dei luoghi in cui è possibile utilizzare un tipo di riga. Ma non puoi accedere ai campi da esso prima che la variabile del record sia stata assegnata.
Stavi confondendo 1. , 3. e 4. e risolto utilizzando 5. invece.
Ma c'è altro che va storto qui:
-
Stai selezionando un'intera tabella, ma una variabile di riga (record) può contenere solo una riga alla volta. Quindi solo il primo viene assegnato e restituito. Mentre non c'è
ORDER BY
clausola, il risultato è arbitrario e può cambiare in qualsiasi momento. Trappola del male. -
Dato che ora stai usando un
record
digita, devi assicurarti che sia stato assegnato prima di poter eseguire test sui suoi campi, altrimenti otterrai eccezioni per tabelle vuote. Nel tuo caso il controllorecord_var IS NULL
fa quasi lo stesso lavoro. Ma c'è un caso d'angolo per le righe con NULL in tutti i campi:quindirecord_var IS NULL
restituisce vero. Ancora più complicato per il testIS NOT NULL
. Dettagli qui:Ho aggiunto una demo a SQL fiddle sotto.
-
La funzione restituisce un singolo scalare (
boolean
) valore. Usa:RETURN false;
Invece di:
RETURN QUERY SELECT false;
Funzione
CREATE FUNCTION check_valid(_tbl regclass)
RETURNS bool AS
$func$
DECLARE
r record;
_row_ct int;
BEGIN
EXECUTE '
SELECT is_valid, hit_count, hit_limit
FROM ' || _tbl || '
ORDER <whatever>
LIMIT 1' -- replace <whatever> with your sort criteria
INTO r; -- only needed columns
GET DIAGNOSTICS _row_ct = ROW_COUNT;
IF _row_ct = 0 THEN -- necessary, because r may not be assigned
RETURN false;
ELSIF NOT r.is_valid OR r.hit_count > r.hit_limit THEN
RETURN false;
END IF;
RETURN true;
END
$func$ LANGUAGE plpgsql;
SQL Fiddle (con due varianti della funzione e una demo per la riga IS NULL).
Punti principali
-
Usa
GET DIAGNOSTICS
per scoprire se sono state trovate righe in un'istruzione dinamica conEXECUTE
. -
Il
IF
l'espressione può essere semplificata. -
Il parametro è di tipo
regclass
, non solo un nome di tabella. Non userei il nome fuorviante "tablename" per questo parametro. Ciò non fa che aumentare la tua confusione iniziale. Chiamandolo_tbl
invece.
Se vuoi anche restituire un insieme di tipo di riga variabile: