To zależy od tego, co dokładnie chcesz przetestować .
Schemat informacyjny?
Aby dowiedzieć się, „czy tabela istnieje” ( bez względu na to, kto o to pyta ), wysłanie zapytania do schematu informacyjnego ( information_schema.tables
) jest niepoprawne , ściśle mówiąc, ponieważ ( zgodnie z dokumentacją ):
Wyświetlane są tylko te tabele i widoki, do których bieżący użytkownik ma dostęp (będąc właścicielem lub posiadającym pewne uprawnienia).
Zapytanie dostarczone przez @kong może zwrócić FALSE
, ale tabela może nadal istnieć. Odpowiada na pytanie:
Jak sprawdzić, czy tabela (lub widok) istnieje, a aktualny użytkownik ma do niej dostęp?
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'schema_name'
AND table_name = 'table_name'
);
Schemat informacji jest przydatny głównie w celu zachowania przenośności między głównymi wersjami i różnymi systemami RDBMS. Ale implementacja jest powolna, ponieważ Postgres musi używać wyrafinowanych widoków, aby zachować zgodność ze standardem ( information_schema.tables
jest to raczej prosty przykład). A niektóre informacje (takie jak OID) giną podczas tłumaczenia z katalogów systemowych - co w rzeczywistości zawierają wszystkie informacje.
Katalogi systemowe
Twoje pytanie brzmiało:
Jak sprawdzić, czy istnieje stół?
SELECT EXISTS (
SELECT FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'schema_name'
AND c.relname = 'table_name'
AND c.relkind = 'r' -- only tables
);
Korzystaj z katalogów systemowych pg_class
i pg_namespace
bezpośrednio, co jest również znacznie szybsze. Jednak zgodnie z dokumentacją dotyczącąpg_class
:
Katalog pg_class
kataloguje tabele i większość innych elementów, które mają kolumny lub są w inny sposób podobne do tabeli. Obejmuje to indeksy (ale zobacz także pg_index
), sekwencje , widoki , widoki zmaterializowane , typy złożone i tabele TOAST ;
W przypadku tego konkretnego pytania możesz również użyć widoku systemowegopg_tables
. Nieco prostsze i bardziej przenośne w głównych wersjach Postgres (co nie stanowi problemu w przypadku tego podstawowego zapytania):
SELECT EXISTS (
SELECT FROM pg_tables
WHERE schemaname = 'schema_name'
AND tablename = 'table_name'
);
Identyfikatory muszą być unikalne wśród wszystkich wymienionych powyżej obiektów. Jeśli chcesz zapytać:
Jak sprawdzić, czy jest przyjmowana nazwa tabeli lub podobnego obiektu w danym schemacie?
SELECT EXISTS (
SELECT FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'schema_name'
AND c.relname = 'table_name'
);
Alternatywa: rzut do regclass
SELECT 'schema_name.table_name'::regclass
Powoduje to wyjątek, jeśli (opcjonalnie kwalifikowana według schematu) tabela (lub inny obiekt zajmujący tę nazwę) nie istnieje.
Jeśli nazwa tabeli nie zostanie zakwalifikowana przez schemat, rzutowanie na wartość regclass
domyślną search_path
i zwróci OID dla pierwszej znalezionej tabeli - lub wyjątek, jeśli tabela nie znajduje się w żadnym z wymienionych schematów. Zwróć uwagę, że schematy systemowe pg_catalog
i pg_temp
(schemat tymczasowych obiektów bieżącej sesji) są automatycznie częścią search_path
.
Możesz tego użyć i złapać możliwy wyjątek w funkcji. Przykład:
Zapytanie takie jak powyżej pozwala uniknąć możliwych wyjątków i dlatego jest nieco szybsze.
Teraz dużo prostsze:
SELECT to_regclass('schema_name.table_name');
To samo co obsada, ale powraca ...
... null zamiast zgłaszać błąd, jeśli nazwa nie zostanie znaleziona
[[ `psql dbname -tAc "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'ejabberd' AND table_name = 'users');"` = 't' ]]
pg_tables
to właściwie dobry pomysł na „Jak sprawdzić, czy tabela istnieje?” (Sprawdzanie tabel tylko ., A nie do innych celów, jak wyjaśniono powyżej Ponadto,pg_tables
jest widokiem z udziałem kilku tabel (pg_class
,pg_namespace
,pg_tablespace
), który jest nieco droższy Najważniejszym powodem. Jestem przyzwyczajony do zapytaniapg_class
bezpośrednio i nie pomyśl,pg_tables
pisząc tę odpowiedź. Dodałem ją powyżej teraz, dzięki.pg_my_temp_schema()
aby uzyskać identyfikator OID rzeczywistego schematu tymczasowego, jeśli istnieje. (Ale widoki w teścieinformation_schema
nie obejmują OIDów. MożnaSELECT nspname FROM pg_namespace WHERE OID = pg_my_temp_schema()
) Twój test ma kilka słabych punktów. Prawidłowe badanie byłobytable_schema LIKE 'pg\_temp\_%'
lub surowszych:table_schema ~ '^pg_temp_\d+$'
.Być może użyj schematu information_schema :
źródło
Dla PostgreSQL 9.3 lub starszego ... Lub kto lubi wszystko znormalizowane do tekstu
Trzy smaki mojej starej biblioteki SwissKnife:
relname_exists(anyThing)
,relname_normalized(anyThing)
irelnamechecked_to_array(anyThing)
. Wszystkie sprawdzenia z tabeli pg_catalog.pg_class i zwracają standardowe uniwersalne typy danych ( boolean , text lub text []).źródło