Важно е да разберете основното естество на тези пет различни вида данни/символ :
1. 'my_tbl'
Литерал на низ от unknown вида . Когато се използва в SQL (вграден в plpgsql код или не), той се принуждава към тип, извлечен от контекста . Ако типът не може да бъде определен, може да се наложи изрично преобразуване. Като:'my_tbl'::text .
2. 'my_tbl'::text
Същият литерал на низ се прехвърля към тип text . Може да съдържа името на таблица, но всъщност е просто текст.
3. 'my_tbl'::regclass
идентификатор на обект (OID)
за регистриран клас . Той се показва и може да бъде въведен като низ, представляващ валидно име на обект ('my_tbl' ). Резултатът е автоматично квалифициран като схема ('my_schema.my_tbl' ) и/или в двойни кавички ('"mY_TbL"' ), ако би било двусмислено или незаконно по друг начин. Може да бъде обикновена маса , последователност , преглед , материализиран изглед , съставен тип и т.н. Подробности в този свързан отговор:
4. my_tbl_var my_tbl (съкратено от my_tbl_var my_tbl%ROWTYPE )
В DECLARE раздел на plpgsql кодов блок, който е декларация на променлива с добре познат тип ред
(известен още като композитен тип). Типът трябва да бъде регистриран в системната таблица pg_class (същото като с regclass променлива). Това не е OID на реферирания обект, а действителният му тип ред. my_tbl_var и my_tbl и двете са идентификатори тук и не може да се параметризира. Можете също да прехвърляте всеки ред или запис директно:(123, 'foo')::my_tbl
5. my_tbl_var record
В DECLARE раздел на plpgsql кодов блок, който е декларацията на анонимен запис
. По принцип контейнер за все още неизвестен тип ред / с все още недефинирана структура. Може да се използва в повечето от местата, където може да се използва тип ред. Но не можете да получите достъп до полета от него, преди да бъде присвоена променливата за запис.
Объркахте 1. , 3. и 4. и го реши с помощта на 5. вместо това.
Но има още неща, които се объркват тук:
-
Избирате цяла таблица, но променлива за ред (запис) може да съдържа само един ред наведнъж. Така че само първият се присвоява и връща. Въпреки че няма
ORDER BYклауза, резултатът е произволен и може да се промени по всяко време. Зъл капан. -
Тъй като сега използвате
recordтип, трябва да се уверите, че е присвоен, преди да можете да изпълнявате тестове на неговите полета, или ще получите изключения за празни таблици. Във вашия случай проверкатаrecord_var IS NULLвърши почти същата работа. Но има ъглов случай за редове с NULL във всички полета:тогаваrecord_var IS NULLоценява като вярно. Още по-трудно за тестаIS NOT NULL. Подробности тук:Добавих демонстрация към SQL fiddle по-долу.
-
Функцията връща единичен скалар (
boolean) стойност. Използвайте:RETURN false;Вместо:
RETURN QUERY SELECT false;
Функция
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 (с два варианта на функцията и демонстрация за ред IS NULL).
Основни точки
-
Използвайте
GET DIAGNOSTICSза да разберете дали са намерени редове в динамичен оператор сEXECUTE. -
IFизразът може да бъде опростен. -
Параметърът е от тип
regclass, а не просто име на таблица. Не бих използвал подвеждащото име "tablename" за този параметър. Това само допринася за първоначалното ви объркване. Наричайки го_tblвместо това.
Ако искате също да върнете набор от променливи тип ред: