如何检查给定模式中是不是存在表
Posted
技术标签:
【中文标题】如何检查给定模式中是不是存在表【英文标题】:How to check if a table exists in a given schema如何检查给定模式中是否存在表 【发布时间】:2014-01-02 03:59:18 【问题描述】: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 或更高版本。
【问题讨论】:
如果存在......如果不存在......没有 [] 【参考方案1】:这取决于您要准确地测试什么。
信息架构?
要查找“表是否存在”(不管是谁问),查询信息模式(information_schema.tables
)严格来说是不正确的,因为(@ 987654321@):
仅显示当前用户有权访问的那些表和视图 到(通过成为所有者或拥有某些特权)。
查询provided by @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_class
和pg_namespace
,速度也快很多。但是,per documentation on pg_class
:
目录
pg_class
目录表和大多数其他具有 列或在其他方面类似于表。这包括索引(但 另见pg_index
)、序列、视图、物化视图、复合 类型和TOAST表;
对于这个特定的问题,您也可以使用system view 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'
);
Related answer on dba.SE discussing "Information schema vs. system catalogs"
替代方案:转换为regclass
SELECT 'schema_name.table_name'::regclass
如果(可选的模式限定)表(或占用该名称的其他对象)不存在,这引发异常。
如果您不对表名进行模式限定,则强制转换为 regclass
默认为 search_path
并返回找到的第一个表的 OID - 如果表不在任何列出的模式中,则返回异常。请注意,系统架构 pg_catalog
和 pg_temp
(当前会话的临时对象的架构)自动成为 search_path
的一部分。
您可以使用它并在函数中捕获可能的异常。示例:
Check if sequence exists in Postgres (plpgsql)像上面这样的查询避免了可能的异常,因此速度稍快。
to_regclass(rel_name)
在 Postgres 9.4+ 中
现在简单多了:
SELECT to_regclass('schema_name.table_name');
与演员相同,but it returns ...
... null 而不是在找不到名称时抛出错误
【讨论】:
来自外壳:[[ `psql dbname -tAc "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'ejabberd' AND table_name = 'users');"` = 't' ]]
您有什么理由不使用pg_tables?
pg_tables
对于“如何检查表是否存在?”(仅检查表,不检查其他用途,和上面解释的一样。另外,pg_tables
是一个涉及多个表的视图(pg_class
,pg_namespace
,pg_tablespace
),这有点贵。最重要的原因:我习惯于查询@987654361 @直接@,写这个答案的时候没有想到pg_tables
。我现在加在上面,谢谢。
@sage88:是的,我删除了我不正确的评论。您可以使用pg_my_temp_schema()
来获取实际临时架构的 OID(如果存在)。 (但information_schema
中的视图不包括 OID。您可以SELECT nspname FROM pg_namespace WHERE OID = pg_my_temp_schema()
)您的测试有几个弱点。正确的测试应该是 table_schema LIKE 'pg\_temp\_%'
或更严格的:table_schema ~ '^pg_temp_\d+$'
。
@PeterKrauss 如果您尝试在 9.4 之前的 postgres 版本上使用 to_regclass 函数,您将收到该错误。必须有 9.4+【参考方案2】:
也许用information_schema:
SELECT EXISTS(
SELECT *
FROM information_schema.tables
WHERE
table_schema = 'company3' AND
table_name = 'tableincompany3schema'
);
【讨论】:
【参考方案3】:对于 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;
【讨论】:
【参考方案4】:来自https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-PATTERNS
例如,\dt foo*.bar 显示其表名的所有表 包括模式名称以 foo 开头的模式中的 bar。
【讨论】:
以上是关于如何检查给定模式中是不是存在表的主要内容,如果未能解决你的问题,请参考以下文章