Belirli bir şemada bir tablo olup olmadığı nasıl kontrol edilir


154

Postgres 8.4 ve üzeri veritabanları, publicşemada ortak tablolar ve şemada şirkete özgü tablolar içerir company.
companyşema adları her zaman 'company'şirket numarası ile başlar ve biter.
Dolayısıyla, aşağıdaki gibi şemalar olabilir:

public
company1
company2
company3
...
companynn

Bir uygulama her zaman tek bir firma ile çalışır.
Aşağıdaki search_pathgibi odbc veya npgsql bağlantı dizesinde buna göre belirtilir:

search_path='company3,public'

Belirli bir tablonun belirli bir companynşemada olup olmadığını nasıl kontrol edersiniz ?

Örneğin:

select isSpecific('company3','tablenotincompany3schema')

geri dönmeli falseve

select isSpecific('company3','tableincompany3schema')

dönmelidir true.

Her durumda, işlev companyndiğer şemaları değil, yalnızca geçirilen şemayı kontrol etmelidir .

Verilen bir tablo her ikisinde de publicve geçirilen şemada mevcutsa , işlev geri dönmelidir true.
Postgres 8.4 veya üzeri için çalışmalıdır.

Yanıtlar:


294

Bu test etmek istediğinize bağlıdır aynen .

Bilgi şeması?

"Tablonun var olup olmadığını" bulmak için ( kim sorarsa sorsun), bilgi şemasını ( information_schema.tables) sorgulamak yanlıştır , çünkü ( belgelere göre ):

Yalnızca mevcut kullanıcının erişime sahip olduğu bu tablolar ve görünümler gösterilir (sahip olarak veya bazı ayrıcalıklara sahip olarak).

@Kong tarafından sağlanan sorgu geri dönebilir FALSE, ancak tablo hala var olabilir. Soruyu cevaplar:

Bir tablonun (veya görünümün) mevcut olup olmadığı ve mevcut kullanıcının buna erişimi olup olmadığı nasıl kontrol edilir?

SELECT EXISTS (
   SELECT FROM information_schema.tables 
   WHERE  table_schema = 'schema_name'
   AND    table_name   = 'table_name'
   );

Bilgi şeması, temel olarak büyük sürümlerde ve farklı RDBMS'de taşınabilir kalmak için kullanışlıdır. Ancak uygulama yavaştır, çünkü Postgres standarda uymak için sofistike görünümler kullanmak zorundadır ( information_schema.tablesoldukça basit bir örnektir). Ve bazı bilgiler (OID'ler gibi), aslında tüm bilgileri taşıyan sistem kataloglarındaki çeviride kaybolur .

Sistem katalogları

Sorunuz şuydu:

Bir masanın var olup olmadığı nasıl kontrol edilir?

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
   );

Sistem kataloglarını pg_classve pg_namespacedoğrudan kullanın, bu da oldukça hızlıdır. Bununla birlikte, aşağıdaki belgelere görepg_class :

Katalog pg_classkataloglar tabloları ve sütunları olan veya bir tabloya aksi benzer başka her şeyi. Buna indeksler (ama ayrıca bakın pg_index), diziler , görünümler , somutlaştırılmış görünümler , bileşik tipler ve TOAST tabloları dahildir ;

Bu belirli soru için sistem görünümünüpg_tables de kullanabilirsiniz . Başlıca Postgres sürümlerinde biraz daha basit ve daha taşınabilir (bu temel sorgu için pek de endişe verici değildir):

SELECT EXISTS (
   SELECT FROM pg_tables
   WHERE  schemaname = 'schema_name'
   AND    tablename  = 'table_name'
   );

Tanımlayıcıların yukarıda bahsedilen tüm nesneler arasında benzersiz olması gerekir . Sormak istersen:

Belirli bir şemadaki bir tablo veya benzer bir nesne için bir adın alındığı nasıl kontrol edilir?

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'
   );

Alternatif: yayınlama regclass

SELECT 'schema_name.table_name'::regclass

Bu , (isteğe bağlı olarak şema nitelikli) tablo (veya bu adı kullanan başka bir nesne) yoksa bir istisna oluşturur .

Tablo adını şema olarak nitelendirmezseniz, bulunan ilk tablo için regclassvarsayılana search_pathçevirme ve OID'yi döndürür veya tablo listelenen şemaların hiçbirinde değilse bir istisna. Sistem şemalarının pg_catalogve pg_temp(mevcut oturumun geçici nesneleri için şema) otomatik olarak search_path.

Bunu kullanabilir ve bir işlevde olası bir istisnayı yakalayabilirsiniz. Misal:

Yukarıdaki gibi bir sorgu olası istisnaları önler ve bu nedenle biraz daha hızlıdır.

to_regclass(rel_name) Postgres 9.4+ sürümünde

Şimdi çok daha basit:

SELECT to_regclass('schema_name.table_name');

Oyuncularla aynı, ama geri dönüyor ...

... isim bulunmazsa bir hata atmak yerine boş


4
kabuktan:[[ `psql dbname -tAc "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'ejabberd' AND table_name = 'users');"` = 't' ]]
brauliobo

1
Pg_tables kullanmamanızın herhangi bir nedeni var mı ?
m0meni

1
pg_tablesaslında "Bir tablonun var olup olmadığı nasıl kontrol edilir?" için iyi bir fikirdir. (Denetleniyor sadece tablolar ., Başka amaçlar için, gibi yukarıda açıklanmayan Ayrıca, pg_tablesçeşitli tablolar içeren bir görünümüdür ( pg_class, pg_namespace, pg_tablespace), biraz daha pahalı olan en önemli nedeni:. Ben sorguya alışkınım pg_classdoğrudan ve vermedi pg_tablesbu cevabı yazarken bir düşünün . Şimdi yukarı ekledim, teşekkürler.
Erwin Brandstetter

1
@ sage88: Doğru, yanlış yorumumu kaldırdım. pg_my_temp_schema()Varsa, gerçek geçici şemanın OID'sini almak için kullanabilirsiniz . (Ancak içindeki görünümler information_schemaOID'leri içermez. Yapabilirsin SELECT nspname FROM pg_namespace WHERE OID = pg_my_temp_schema()) Testinizin birkaç zayıf yönü vardır. Doğru bir sınav olacağını table_schema LIKE 'pg\_temp\_%'veya daha katı: table_schema ~ '^pg_temp_\d+$'.
Erwin Brandstetter

1
@PeterKrauss 9.4'ten daha eski postgres sürümünde to_regclass işlevini kullanmaya çalışırsanız bu hatayı alırsınız. 9,4+ olmalıdır
spetz83

44

Belki kullanmak information_schema :

SELECT EXISTS(
    SELECT * 
    FROM information_schema.tables 
    WHERE 
      table_schema = 'company3' AND 
      table_name = 'tableincompany3schema'
);

0

PostgreSQL 9.3 veya daha azı için ... Veya metne göre normalleştirilmiş her şeyi seven

Üç eski SwissKnife kütüphanesinin tatlar: relname_exists(anyThing), relname_normalized(anyThing)ve relnamechecked_to_array(anyThing). Pg_catalog.pg_class tablosundaki tüm kontroller ve standart evrensel veri türlerini ( boole , metin veya metin []) döndürür .

/**
 * From my old SwissKnife Lib to your SwissKnife. License CC0.
 * Check and normalize to array the free-parameter relation-name.
 * Options: (name); (name,schema), ("schema.name"). Ignores schema2 in ("schema.name",schema2).
 */
CREATE FUNCTION relname_to_array(text,text default NULL) RETURNS text[] AS $f$
     SELECT array[n.nspname::text, c.relname::text]
     FROM   pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace,
            regexp_split_to_array($1,'\.') t(x) -- not work with quoted names
     WHERE  CASE
              WHEN COALESCE(x[2],'')>'' THEN n.nspname = x[1]      AND c.relname = x[2]
              WHEN $2 IS NULL THEN           n.nspname = 'public'  AND c.relname = $1
              ELSE                           n.nspname = $2        AND c.relname = $1
            END
$f$ language SQL IMMUTABLE;

CREATE FUNCTION relname_exists(text,text default NULL) RETURNS boolean AS $wrap$
  SELECT EXISTS (SELECT relname_to_array($1,$2))
$wrap$ language SQL IMMUTABLE;

CREATE FUNCTION relname_normalized(text,text default NULL,boolean DEFAULT true) RETURNS text AS $wrap$
  SELECT COALESCE(array_to_string(relname_to_array($1,$2), '.'), CASE WHEN $3 THEN '' ELSE NULL END)
$wrap$ language SQL IMMUTABLE;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.