Ważne jest, aby zrozumieć podstawową naturę tych pięciu różnych rodzajów danych/symbolów :
1. 'my_tbl'
Literał ciągu znaków unknown
wpisz . Gdy jest używany w SQL (osadzony w kodzie plpgsql lub nie), jest przypisywany do typu pochodzącego z kontekstu . Jeśli nie można określić typu, może być wymagane jawne rzutowanie. Na przykład:'my_tbl'::text
.
2. 'my_tbl'::text
Ten sam literał ciągu znaków rzutowany na wpisz text
. Może zawierać nazwę tabeli, ale tak naprawdę to tylko tekst.
3. 'my_tbl'::regclass
identyfikator obiektu (OID)
dla zarejestrowanej klasy . Jest wyświetlany i może być wprowadzony jako ciąg znaków reprezentujący poprawną nazwę obiektu ('my_tbl'
). Dane wyjściowe są automatycznie kwalifikowane według schematu ('my_schema.my_tbl'
) i / lub w cudzysłowie ('"mY_TbL"'
), jeśli byłoby to niejednoznaczne lub niezgodne z prawem. Może to być zwykły stół , sekwencja , wyświetl , widok zmaterializowany , typ złożony itp. Szczegóły w tej powiązanej odpowiedzi:
4. my_tbl_var my_tbl
(skrót od my_tbl_var my_tbl%ROWTYPE
)
W DECLARE
sekcja bloku kodu plpgsql, która jest deklaracją zmiennej z dobrze znanym typ wiersza
(alias typu kompozytowego). Typ musi być zarejestrowany w tabeli systemowej pg_class
(tak samo jak z regclass
zmienny). Nie jest to OID obiektu, do którego się odwołuje, ale jego rzeczywisty typ wiersza. my_tbl_var
i my_tbl
oba są identyfikatorami tutaj i nie można go sparametryzować. Możesz także rzutować dowolny wiersz lub rekord bezpośrednio:(123, 'foo')::my_tbl
5. my_tbl_var record
W DECLARE
sekcja bloku kodu plpgsql, która jest deklaracją anonimowego nagraj
. Zasadniczo symbol zastępczy dla jeszcze nieznanego typu wiersza / o jeszcze niezdefiniowanej strukturze. Może być używany w większości miejsc, w których można użyć typu wiersza. Ale nie możesz uzyskać z niego dostępu do pól przed przypisaniem zmiennej rekordu.
Myliłeś się 1. , 3. i 4. i rozwiązał go za pomocą 5. zamiast tego.
Ale więcej dzieje się źle tutaj:
-
Wybierasz całą tabelę, ale zmienna wierszowa (rekordowa) może zawierać tylko jeden wiersz na raz. Tak więc tylko pierwszy jest przypisywany i zwracany. Chociaż nie ma
ORDER BY
klauzuli, wynik jest dowolny i może ulec zmianie w dowolnym momencie. Zła pułapka. -
Ponieważ używasz teraz
record
typu, musisz upewnić się, że został przypisany, zanim będziesz mógł uruchomić testy na jego polach, w przeciwnym razie otrzymasz wyjątki dla pustych tabel. W Twoim przypadku sprawdźrecord_var IS NULL
prawie wykonuje tę samą pracę. Ale istnieje przypadek narożny dla wierszy z NULL we wszystkich polach:wtedyrecord_var IS NULL
ocenia się jako prawda. Jeszcze trudniejsze dla testuIS NOT NULL
. Szczegóły tutaj:Dodałem demo do skrzypce SQL poniżej.
-
Funkcja zwraca pojedynczy skalar (
boolean
) wartość. Użyj:RETURN false;
Zamiast:
RETURN QUERY SELECT false;
Funkcja
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;
Skrzypce SQL (z dwoma wariantami funkcji i demonstracją wiersza IS NULL).
Główne punkty
-
Użyj
GET DIAGNOSTICS
aby dowiedzieć się, czy w instrukcji dynamicznej znaleziono jakieś wiersze za pomocąEXECUTE
. -
IF
wyrażenie może być uproszczone. -
Parametr jest typu
regclass
, a nie tylko nazwę tabeli. Nie użyłbym mylącej nazwy „tablename” dla tego parametru. To tylko zwiększa twoje początkowe zamieszanie. Nazywam to_tbl
zamiast tego.
Jeśli chcesz także zwrócić zestaw zmiennych typów wierszy: