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 BYklauzuli, wynik jest dowolny i może ulec zmianie w dowolnym momencie. Zła pułapka. -
Ponieważ używasz teraz
recordtypu, 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 NULLprawie wykonuje tę samą pracę. Ale istnieje przypadek narożny dla wierszy z NULL we wszystkich polach:wtedyrecord_var IS NULLocenia 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 DIAGNOSTICSaby dowiedzieć się, czy w instrukcji dynamicznej znaleziono jakieś wiersze za pomocąEXECUTE. -
IFwyraż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_tblzamiast tego.
Jeśli chcesz także zwrócić zestaw zmiennych typów wierszy: