首页 文章

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

提问于
浏览
107

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

public
company1
company2
company3
...
companynn

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

search_path='company3,public'

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

select isSpecific('company3','tablenotincompany3schema')

应该返回 false ,和

select isSpecific('company3','tableincompany3schema')

应该返回 true .

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

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

3 回答

  • 205

    这取决于你想要测试的内容 exactly .

    信息架构?

    要查找"whether the table exists"(无论是谁问),严格来说,查询信息模式( information_schema.tables )是 incorrect ,因为(per documentation):

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

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

    How to check whether a table (or view) exists, and the current user has access to it?

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

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

    系统目录

    你的问题是:

    How to check whether a table exists?

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

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

    How to check whether a name for a table or similar object in a given schema is taken?

    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,而不是在找不到名称时抛出错误

  • 0

    也许使用information_schema

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

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

    我的旧SwissKnife图书馆的三种口味: relname_exists(anyThing)relname_normalized(anyThing)relnamechecked_to_array(anyThing) . 所有来自pg_catalog.pg_class表的检查,并返回标准通用数据类型(boolean,text或text []) .

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

相关问题