195

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 或更高版本。

4

4 回答 4

353

这取决于您要准确测试的内容。

信息架构?

要查找“表是否存在”(无论是谁询问) ,严格来说,查询信息架构 ( information_schema.tables) 是不正确的,因为(根据文档):

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

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

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

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

信息模式主要用于保持跨主要版本和跨不同 RDBMS 的可移植性。但是实现起来很慢,因为 Postgres 必须使用复杂的视图来遵守标准(information_schema.tables这是一个相当简单的例子)。一些信息(如 OID)在系统目录的翻译过程中丢失了——这些目录实际上承载了所有信息。

系统目录

你的问题是:

如何检查表是否存在?

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

直接使用系统目录pg_classpg_namespace这也快得多。但是,根据以下文档pg_class

目录对pg_class表和大多数其他具有列或与表类似的内容进行编目。这包括索引(但另见pg_index)、序列视图物化视图复合类型TOAST 表

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

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

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

如何检查给定模式中的表或类似对象的名称是否被采用?

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

替代方案:强制转换为regclass

SELECT 'schema_name.table_name'::regclass

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

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

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

像上面这样的查询避免了可能的异常,因此速度稍快。

to_regclass(rel_name)在 Postgres 9.4+

现在简单多了:

SELECT to_regclass('schema_name.table_name');

与演员相同,它返回......

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

于 2014-06-06T19:58:11.623 回答
49

也许使用information_schema

SELECT EXISTS(
    SELECT * 
    FROM information_schema.tables 
    WHERE 
      table_schema = 'company3' AND 
      table_name = 'tableincompany3schema'
);
于 2013-12-14T13:45:23.647 回答
0

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

我的旧 SwissKnife 库的三种风格relname_exists(anyThing)relname_normalized(anyThing)relnamechecked_to_array(anyThing). 从pg_catalog.pg_class表中进行所有检查,并返回标准通用数据类型(booleantexttext [])。

/**
 * 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;
于 2017-11-18T01:24:24.350 回答
0

来自https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-PATTERNS

例如,\dt foo*。bar显示所有表名包含 bar 的表,这些表位于模式名以 foo 开头的模式中。

于 2021-09-24T10:45:39.090 回答