PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PLPGSQL - Verwenden Sie den dynamischen Tabellennamen in der Declare -Anweisung

Es ist wichtig, die Haupt Natur dieser fünf verschiedenen Arten von Daten / Symbolen zu verstehen. :

1. 'my_tbl'

Eine Zeichenfolge, die wörtlich von Unbekannt Typ . Bei Verwendung in SQL (eingebettet in PLPGSQL -Code oder nicht) wird er zu einem vom -Kontext abgeleiteten Typ gezwungen. . Wenn der Typ nicht bestimmt werden kann, kann ein explizites Guss erforderlich sein. Gefällt: 'my_tbl' ::text .

2. 'my_tbl' ::text

Die gleiche Zeichenfolge. . Es kann den Namen einer Tabelle halten, aber es ist wirklich nur Text.

3. 'my_tbl' ::Regclass

An Objektkennung (OID) Für eine registrierte Klasse . Es wird angezeigt und kann als Zeichenfolge eingegeben werden, die einen gültigen Objektnamen darstellt ( 'my_tbl' ). Die Ausgabe wird automatisch schema-qualifiziert ( 'my_schema.my_tbl' ) und / oder doppelt zitiert ( '"my_tbl"' ) Wenn es ansonsten mehrdeutig oder illegal wäre. Es kann eine reguläre Tabelle sein , Sequenz , view , materialisierte Ansicht , Composite -Typ usw. Details in dieser zugehörigen Antwort:

4. my_tbl_var my_tbl (Kurz für my_tbl_var my_tbl%rowType )

Im deklarieren Abschnitt eines PLPGSQL-Codeblocks, der eine variable Deklaration mit einem bekannten Zeilentyp (a.k.a. Composite -Typ). Der Typ muss in der Systemtabelle pg_class registriert werden (Gleich wie bei einem Regclass Variable). Es ist nicht die OID des referenzierten Objekts, sondern der tatsächliche Zeilentyp. my_tbl_var und my_tbl sind beide identifiers hier und kann nicht parametrisiert werden. Sie können auch jede Zeile oder Aufzeichnung direkt aufnehmen: (123, 'foo') ::my_tbl

5. my_tbl_var record

Im deklarieren Abschnitt eines PLPGSQL-Codeblocks, der die Deklaration eines anonymen rekord . Grundsätzlich ein Platzhalter für einen noch unbekannten Zeilentyp / mit noch undefinierter Struktur. Es kann in meiste verwendet werden Von den Stellen kann ein Zeilentyp verwendet werden. Sie können jedoch nicht darauf zugreifen, bevor die Datensatzvariable zugewiesen wird.

Sie verwirrten 1. , 3. und 4. und löste es mit 5. Stattdessen.
Aber es gibt mehr schief Hier:

  • Sie wählen eine ganze Tabelle aus, aber eine Zeilenvariable (Datensatz) kann jeweils nur eine Zeile halten. Also wird nur der erste zugewiesen und zurückgegeben. Während es keine bestellen nach gibt Klausel, das Ergebnis ist willkürlich und kann sich jederzeit ändern. böse Falle.

  • Da Sie jetzt einen -Ertrat verwenden Geben Sie ein, Sie müssen sicherstellen, dass es zugewiesen wurde, bevor Sie Tests auf den Feldern ausführen können, oder Sie erhalten Ausnahmen für leere Tabellen. In Ihrem Fall ist der Check record_var null Fast den gleichen Job. In allen Feldern gibt es jedoch einen Eckfall für Zeilen mit Null:dann record_var ist null bewertet true. Noch schwieriger für den Test ist nicht null . Details hier:

    Ich habe der SQL Fiddle eine Demo hinzugefügt. unten.

  • Die Funktion gibt einen einzelnen Skalar zurück ( boolean ) Wert. Verwendung:

    RETURN false;
    

    Statt:

    RETURN QUERY SELECT false;

Funktion

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 (mit zwei Varianten der Funktion und einer Demo für Zeile ist null).

Wichtige Punkte

  • Verwenden Sie Diagnostics Um herauszufinden, ob Zeilen in einer dynamischen Anweisung mit ausführen gefunden wurden .

  • Der if Ausdruck kann vereinfacht werden.

  • Der Parameter ist vom Typ Regclass vom Typ , nicht nur ein tischfeiname. Ich würde den irreführenden Namen "TableName" für diesen Parameter nicht verwenden. Das trägt nur zu Ihrer anfänglichen Verwirrung bei. Rufen Sie es _tbl auf Stattdessen.

Wenn Sie auch zurücksenden möchten Ein Satz variabler Zeilentyp: