PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

plpgsql - utilizzando il nome della tabella dinamica nell'istruzione dichiara

È 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 controllo record_var IS NULL fa quasi lo stesso lavoro. Ma c'è un caso d'angolo per le righe con NULL in tutti i campi:quindi record_var IS NULL restituisce vero. Ancora più complicato per il test IS 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 con EXECUTE .

  • 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: