sql >> Databasteknik >  >> RDS >> PostgreSQL

plpgsql - använder dynamiskt tabellnamn i declare-satsen

Det är viktigt att förstå den huvudsakliga karaktären hos dessa fem olika typer av data/symbol :

1. 'my_tbl'

En bokstavlig sträng av unknown typ . När den används i SQL (inbäddad i plpgsql-kod eller inte), tvingas den till en typ som härrör från kontexten . Om typen inte kan bestämmas kan en explicit gjutning krävas. Gilla:'my_tbl'::text .

2. 'my_tbl'::text

Samma bokstavssträng cast till skriv text . Den kan innehålla namnet på en tabell, men det är egentligen bara text.

3. 'my_tbl'::regclass

En objektidentifierare (OID) för en registrerad klass . Den visas och kan matas in som en sträng som representerar ett giltigt objektnamn ('my_tbl' ). Utdata är automatiskt schemakvalificerat ('my_schema.my_tbl' ) och/eller dubbla citattecken ('"mY_TbL"' ) om det annars skulle vara tvetydigt eller olagligt. Det kan vara ett vanligt bord , sekvens , visa , materialiserad vy , sammansatt typ etc. Detaljer i detta relaterade svar:

4. my_tbl_var my_tbl (förkortning av my_tbl_var my_tbl%ROWTYPE )

I DECLARE avsnitt av ett plpgsql-kodblock som är en variabeldeklaration med en välkänd radtyp (a.k.a. sammansatt typ). Typen måste registreras i systemtabellen pg_class (samma som med en regclass variabel). Det är inte OID för det refererade objektet, utan dess faktiska radtyp. my_tbl_var och my_tbl är båda identifierare här och kan inte parametreras. Du kan också casta valfri rad eller spela in direkt:(123, 'foo')::my_tbl

5. my_tbl_var record

I DECLARE avsnitt av ett plpgsql-kodblock som är deklarationen av en anonym rekord . I grund och botten en platshållare för en ännu okänd radtyp / med ännu odefinierad struktur. Den kan användas i de flesta av platserna kan en radtyp användas. Men du kan inte komma åt fält från den innan postvariabeln har tilldelats.

Du förvirrade 1. , 3. och 4. och löste det genom att använda 5. istället.
Men det är mer som går fel här:

  • Du väljer en hel tabell, men en radvariabel (rekord) kan bara hålla en rad åt gången. Så bara den första tilldelas och returneras. Det finns ingen ORDER BY klausul är resultatet godtyckligt och kan ändras när som helst. Ondsk fälla.

  • Eftersom du nu använder en record typ, måste du se till att den har tilldelats innan du kan köra tester på dess fält, annars får du undantag för tomma tabeller. I ditt fall är kryssrutan record_var IS NULL gör nästan samma jobb. Men det finns ett hörnfall för rader med NULL i alla fält:sedan ÄR record_var IS NULL bedöms till sant. Ännu svårare för testet IS NOT NULL . Detaljer här:

    Jag lade till en demo till SQL-fiolen nedan.

  • Funktionen returnerar en enda skalär (boolean ) värde. Använd:

    RETURN false;
    

    Istället för:

    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 (med två varianter av funktionen och en demo för rad IS NULL).

Huvudpunkter

  • Använd GET DIAGNOSTICS för att ta reda på om några rader hittades i en dynamisk sats med EXECUTE .

  • IF uttryck kan förenklas.

  • Parametern är av typen regclass , inte bara ett tabellnamn. Jag skulle inte använda det missvisande namnet "tabellnamn" för den här parametern. Det ökar bara din första förvirring. Kallar det _tbl istället.

Om du också vill återvända en uppsättning variabel radtyp:



  1. Radie på 40 kilometer med latitud och longitud

  2. SQL Fuzzy Matchning

  3. Mysql Välj andra raden

  4. Sql enkel nybörjaroperation