假设我在数据库中创建了一些用户定义的类型,
即 CREATE TYPE abc ...
然后可以确定用户定义的类型是否存在?也许使用任何postgres信息表?
这样做的主要原因是因为PostgreSQL似乎不支持CREATE OR REPLACE TYPE ...
,如果某种类型创建了多次,我希望能够先删除现有的类型,然后重新加载新的类型。
Answers:
我在此处添加了用于在简单脚本中创建类型的完整解决方案,而无需为此创建函数。
--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$$;
regtype
),因此它似乎实际上是更好的解决方案。8)
到目前为止,我发现的最简单的解决方案是受@Cromax的答案启发,可以应对模式:
DO $$ BEGIN
CREATE TYPE my_type AS (/* fields go here */);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
正是您可能真正期望的-我们将CREATE TYPE语句包装在异常处理程序中,这样它才不会中止当前事务。
EXCEPTION
这里是什么意思。类型是否已经过载,或者我可以按原样使用?
select exists (select 1 from pg_type where typname = 'abc' and typnamespace = (select oid from pg_namespace where nspname = 'my_schema'))
。如果使用单模式配置,请用“ public”替换“ my_schema”。
实际上,Postgres没有CREATE OR REPLACE
类型的功能。因此最好的方法是删除它:
DROP TYPE IF EXISTS YOUR_TYPE;
CREATE TYPE YOUR_TYPE AS (
id integer,
field varchar
);
简单的解决方案始终是最好的解决方案。
DROP
将引发错误。但是DROP ... CASCADE
,如果在特定情况下丢失数据是可以接受的,则可以使用它也删除依赖的对象。
为了解决@rog对@bluish答案的困境,使用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'
在您不关心特定于架构的情况下)转换为实际的注册类型。如果确实存在该类型,则不会发生任何“错误”,并且由于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)
如果您使用的是schemas和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'')');