Проверьте, существует ли определенный пользователем тип в PostgreSQL - PullRequest
47 голосов
/ 02 октября 2011

Скажем, я создал несколько пользовательских типов в БД,

т.е. CREATE TYPE abc ...

Можно ли тогда определить, существует ли определенный пользователем тип или нет? Возможно, используя любую из информационных таблиц postgres?

Основная причина этого заключается в том, что PostgreSQL, похоже, не поддерживает CREATE OR REPLACE TYPE ..., и если определенный тип создается несколько раз, я хочу сначала удалить существующий, а затем повторно загрузить новый .

Ответы [ 8 ]

75 голосов
/ 02 февраля 2015

Я добавляю сюда полное решение для создания типов в простом скрипте, без необходимости создания функции только для этой цели.

--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$$;
25 голосов
/ 22 января 2018

Самое простое решение, которое я нашел на сегодняшний день, которое справляется со схемами, вдохновленными ответом @ Cromax, таково:

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

Как раз то, что вы можете ожидать на самом деле - мы просто оборачиваем оператор CREATE TYPE в обработчик исключений, чтобы он не прерывал текущую транзакцию.

17 голосов
/ 02 октября 2011

Вы можете посмотреть в таблице pg_type:

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

Если это правда, то abc существует.

8 голосов
/ 17 января 2017

Действительно, Postgres не имеет функции CREATE OR REPLACE для типов. Так что лучший подход - отбросить это:

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

Простое решение всегда лучшее.

4 голосов
/ 20 января 2018

Чтобы решить дилемму @ 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. Поэтому в следующих строках мы пытаемся уловить эту ошибку, и если это происходит, мы просто создаем наш новый тип данных.

3 голосов
/ 20 августа 2014
-- 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();
-----------------------------------
1 голос
/ 22 июля 2013

Я пытаюсь сделать то же самое, убедитесь, что тип существует.

Я запустил psql с параметром --echo-hidden (-E) и ввел \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);
0 голосов
/ 25 апреля 2018

Более общее решение

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...