[英]Check if a user-defined type already exists in PostgreSQL
假设我在数据库中创建了一些用户定义的类型,
即CREATE TYPE abc...
那么是否可以确定用户定义的类型是否存在? 也许,使用任何 postgres 信息表?
主要原因是因为 PostgreSQL 似乎不支持CREATE OR REPLACE TYPE...
,如果多次创建某个类型,我希望能够先删除现有的,然后重新加载新的一。
我在这里添加了在简单脚本中创建类型的完整解决方案,而无需为此目的创建函数。
--create types
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'my_type') THEN
CREATE TYPE my_type AS
(
--my fields here...
);
END IF;
--more types here...
END$$;
到目前为止,我发现的最简单的解决方案是在@Cromax 的回答的启发下处理模式:
DO $$ BEGIN
CREATE TYPE my_type AS (/* fields go here */);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
正如您所期望的那样 - 我们只是将 CREATE TYPE 语句包装在异常处理程序中,因此它不会中止当前事务。
事实上,Postgres 没有类型的CREATE OR REPLACE
功能。 所以最好的方法是放弃它:
DROP TYPE IF EXISTS YOUR_TYPE;
CREATE TYPE YOUR_TYPE AS (
id integer,
field varchar
);
简单的解决方案总是最好的。
为了解决regtype
对regtype
的回答的困境,使用regtype
数据类型可能更合适。 考虑一下:
DO $$ BEGIN
PERFORM 'my_schema.my_type'::regtype;
EXCEPTION
WHEN undefined_object THEN
CREATE TYPE my_schema.my_type AS (/* fields go here */);
END $$;
PERFORM
子句类似于SELECT
,但它会丢弃结果,因此基本上我们正在检查是否可以将'my_schema.my_type'
(或者如果您不关心特定于架构'my_type'
则只是'my_type'
)转换为实际注册的类型。 如果类型确实存在,那么不会发生任何“错误”,并且由于RETURN
整个块将结束——没有变化,因为类型my_type
已经存在。 但如果无法进行转换,则会抛出错误代码42704
,其标签为undefined_object
。 因此,在接下来的几行中,我们尝试捕获该错误,如果发生这种情况,我们只需创建新的数据类型。
-- All of this to create a type if it does not exist
CREATE OR REPLACE FUNCTION create_abc_type() RETURNS integer AS $$
DECLARE v_exists INTEGER;
BEGIN
SELECT into v_exists (SELECT 1 FROM pg_type WHERE typname = 'abc');
IF v_exists IS NULL THEN
CREATE TYPE abc AS ENUM ('height', 'weight', 'distance');
END IF;
RETURN v_exists;
END;
$$ LANGUAGE plpgsql;
-- Call the function you just created
SELECT create_abc_type();
-- Remove the function you just created
DROP function create_abc_type();
-----------------------------------
我正在尝试做同样的事情,确保类型存在。
我使用--echo-hidden
( -E
) 选项启动 psql 并输入\\dT
:
$ psql -E
psql (9.1.9)
testdb=> \dT
********* QUERY **********
SELECT n.nspname as "Schema",
pg_catalog.format_type(t.oid, NULL) AS "Name",
pg_catalog.obj_description(t.oid, 'pg_type') as "Description"
FROM pg_catalog.pg_type t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND pg_catalog.pg_type_is_visible(t.oid)
ORDER BY 1, 2;
**************************
List of data types
Schema | Name | Description
--------+------------------+-------------
public | errmsg_agg_state |
(1 row)
如果您正在使用模式和 search_path(我是),那么您可能需要保持pg_catalog.pg_type_is_visible(t.oid)
检查。 我不知道 WHERE 中的所有条件都在做什么,但它们似乎与我的案例无关。 目前使用:
SELECT 1 FROM pg_catalog.pg_type as t
WHERE typname = 'mytype' AND pg_catalog.pg_type_is_visible(t.oid);
更通用的解决方案
CREATE OR REPLACE FUNCTION create_type(name text, _type text) RETURNS
integer AS $$
DECLARE v_exists INTEGER;
BEGIN
SELECT into v_exists (SELECT 1 FROM pg_type WHERE typname = name);
IF v_exists IS NULL THEN
EXECUTE format('CREATE TYPE %I AS %s', name, _type);
END IF;
RETURN v_exists;
END;
$$ LANGUAGE plpgsql;
然后你可以这样称呼它:
select create_type('lwm2m_instancetype', 'enum (''single'',''multiple'')');
这与模式配合得很好,并避免了异常处理:
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_type t
LEFT JOIN pg_namespace p ON t.typnamespace=p.oid
WHERE t.typname='my_type' AND p.nspname='my_schema'
) THEN
CREATE TYPE my_schema.my_type AS (/* fields go here */);
END IF;
END
$$;
受@Cromax 回答的启发,这是使用系统目录信息 function to_regtype
的替代解决方案,该解决方案避免了异常子句的额外开销,但仍检查类型是否存在的正确模式:
DO $$ BEGIN
IF to_regtype('my_schema.abc') IS NULL THEN
CREATE TYPE my_schema.abc ... ;
END IF;
END $$;
在使用默认public
模式的情况下,它看起来像:
DO $$ BEGIN
IF to_regtype('abc') IS NULL THEN
CREATE TYPE abc ... ;
END IF;
END $$;
另一种选择
WITH namespace AS(
SELECT oid
FROM pg_namespace
WHERE nspname = 'my_schema'
),
type_name AS (
SELECT 1 type_exist
FROM pg_type
WHERE typname = 'my_type' AND typnamespace = (SELECT * FROM namespace)
)
SELECT EXISTS (SELECT * FROM type_name);
你应该试试这个:
SELECT * from pg_enum WHERE enumlabel='WHAT YOU WANT';
继续蓝色代码,我们还需要检查 DB 在当前模式中是否有这样的类型。 因为如果 db 在任何 db 模式中具有相同的类型,当前代码将不会创建类型。 所以完整的通用代码将如下所示:
$$
BEGIN
IF NOT EXISTS(select
from pg_type
WHERE typname = 'YOUR_ENUM_NAME'
AND typnamespace in
(SELECT oid FROM pg_catalog.pg_namespace where nspname = "current_schema"())) THEN
CREATE TYPE YOUR_ENUM_NAME AS ENUM (....list of values ....);
END IF;
END
$$;```
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.