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或更高版本。
答案 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_class
和pg_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_catalog
和pg_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)
我的旧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;