检查PostgreSQL中是否已存在用户定义的类型

时间:2011-10-02 06:18:06

标签: postgresql user-defined-types

假设我在数据库中创建了一些用户定义的类型,

即。 CREATE TYPE abc ...

是否可以确定用户定义的类型是否存在?也许,使用任何postgres信息表?

主要原因是因为PostgreSQL似乎不支持CREATE OR REPLACE TYPE ...,并且如果某个类型被多次创建,我希望能够首先删除现有类型,然后重新加载新的。

11 个答案:

答案 0 :(得分:73)

我在这里添加了在简单脚本中创建类型的完整解决方案,而无需为此目的创建函数。

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

答案 1 :(得分:24)

到目前为止,我发现的最简单的解决方案是在@ Cromax的答案的启发下应对模式:

DO $$ BEGIN
    CREATE TYPE my_type AS (/* fields go here */);
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

正是您可能期望的 - 我们只是将CREATE TYPE语句包装在异常处理程序中,因此它不会中止当前事务。

答案 2 :(得分:16)

您可以查看pg_type表:

select exists (select 1 from pg_type where typname = 'abc');

如果是,则abc存在。

答案 3 :(得分:8)

事实上,Postgres没有类型的CREATE OR REPLACE功能。所以最好的方法就是放弃它:

DROP TYPE IF EXISTS YOUR_TYPE;
CREATE TYPE YOUR_TYPE AS (
    id      integer,
    field   varchar
);

简单的解决方案始终是最好的解决方案。

答案 4 :(得分:3)

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

答案 5 :(得分:3)

要解决@ 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。因此,在下一行中,我们尝试捕获该错误,如果发生这种情况,我们只需创建新的数据类型。

答案 6 :(得分:1)

我正在尝试做同样的事情,确保存在一种类型。

我使用--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);

答案 7 :(得分:0)

更通用的解决方案

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

答案 8 :(得分:0)

另一种选择

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

答案 9 :(得分:0)

这与模式配合得很好,并避免了异常处理:

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

答案 10 :(得分:0)

你应该试试这个:

SELECT * from pg_enum WHERE enumlabel='WHAT YOU WANT';