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 kryssrutanrecord_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 ÄRrecord_var IS NULL
bedöms till sant. Ännu svårare för testetIS 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 medEXECUTE
. -
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: