如何检查给定模式中是否存在表

时间:2013-12-14 11:07:45

标签: sql database postgresql information-schema search-path

Postgres 8.4及更高版本的数据库包含public架构中的公用表和company架构中的公司特定表。
company架构名称始终以'company'开头,以公司编号结尾 所以可能有类似的模式:

public
company1
company2
company3
...
companynn

应用程序始终与单个公司合作 在odbc或npgsql连接字符串中相应地指定search_path,如:

search_path='company3,public'

如何检查指定的companyn架构中是否存在给定的表?

例如:

select isSpecific('company3','tablenotincompany3schema')

应该返回false

select isSpecific('company3','tableincompany3schema')

应该返回true

在任何情况下,该函数都应仅检查传递的companyn模式,而不是其他模式。

如果public和传递的模式中都存在给定的表,则该函数应返回true
它适用于Postgres 8.4或更高版本。

3 个答案:

答案 0 :(得分:226)

这取决于您要测试的内容 完全

信息架构?

查找"表格是否存在" (无论是谁提出),严格来说,查询信息架构(information_schema.tables不正确,因为(per documentation) :

  

仅显示当前用户具有访问权限的那些表和视图   (作为所有者或拥有某种特权)。

查询demonstrated by @kong可以返回FALSE,但该表仍然可以存在。它回答了这个问题:

如何检查表(或视图)是否存在,以及当前用户是否可以访问它?

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

信息架构主要用于在主要版本和不同RDBMS之间保持可移植性。但实现速度很慢,因为Postgres必须使用复杂的视图来遵守标准(information_schema.tables是一个相当简单的例子)。并且一些信息(如OID)在系统目录的翻译中丢失 - 实际上携带所有信息。

系统目录

你的问题是:

如何检查表格是否存在?

SELECT EXISTS (
   SELECT 1 
   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
   );

直接使用系统目录pg_classpg_namespace,这也快得多。但是,per documentation on pg_class

  

目录pg_class编目表以及其他大多数表   列或以其他方式类似于表。这包括索引(但是   另请参阅pg_index),序列观看物化视图复合   类型 TOAST表;

对于此特定问题,您还可以使用system view pg_tables。主要的Postgres版本更简单,更便携(这个基本查询几乎不关心):

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

标识符必须在上面提到的所有对象中是唯一的。如果你想问:

如何检查给定架构中的表名或类似对象的名称?

SELECT EXISTS (
   SELECT 1 
   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'
   );

替代方案:强制转换为regclass

SELECT 'schema_name.table_name'::regclass

如果(可选的模式限定的)表(或占用该名称的其他对象)不存在,则此引发异常

如果您没有对表名进行模式限定,则转换为regclass默认为search_path并返回找到的第一个表的OID - 如果表中没有,则返回异常列出的架构。请注意,系统架构pg_catalogpg_temp(当前会话的临时对象的架构)自动成为search_path的一部分。

您可以使用它并在函数中捕获可能的异常。示例:

上述查询可以避免可能的异常,因此会稍快一些。

Postgres 9.4 + 中的

to_regclass(rel_name)

现在简单得多:

SELECT to_regclass('schema_name.table_name');

与演员表相同,but it returns ...

  

... null而不是在找不到名称时抛出错误

答案 1 :(得分:40)

也许使用information_schema

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

答案 2 :(得分:0)

对于PostgreSQL 9.3或更低版本......或者谁喜欢所有标准化为文本

我的旧SwissKnife图书馆有三种版本:relname_exists(anyThing)relname_normalized(anyThing)relnamechecked_to_array(anyThing)。所有来自 pg_catalog.pg_class 表的检查,并返回标准通用数据类型(布尔文本文本 [])

/**
 * 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;