Вставить выбрать из приведения значений


Часто желательно вставлять из выражения SELECT (например, чтобы квалифицировать предложение WHERE), но это может запутать postgresql в типах столбцов.

Пример:

CREATE TABLE example (a uuid primary key, b numeric);
INSERT INTO example 
SELECT a, b 
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)) as data(a,b);
=> ERROR:  column "a" is of type uuid but expression is of type text

Это можно исправить, явно приведя значения:

INSERT INTO example 
SELECT a, b 
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a'::uuid, NULL::numeric)) as data(a,b);

Но это грязно и обременительно для обслуживания. Есть ли способ заставить postgres понять, что выражение VALUES имеет тот же тип, что и строка таблицы, т. е. что-то вроде

VALUES('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)::example%ROWTYPE

Правка:

Предложение использования (data:: example).* аккуратно, но, к сожалению, это полное, кажется, портит планировщик запросов postgres в сочетании с предложением WHERE, таким как:

INSERT INTO example 
SELECT (data::example).* 
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL)) as data 
WHERE NOT EXISTS (SELECT * FROM example 
                  WHERE (data::example) 
                  IS NOT DISTINCT FROM example);

Это занимает минуты с большим столом.

2 3

2 ответа:

Вы можете привести запись к типу строки вашей таблицы:

INSERT INTO example 
SELECT (data::example).*
FROM (
    VALUES 
      ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL),
      ('54514c89-f188-490a-abbb-268f9154ab2c', 42)
) as data;

data::example приводит всю строку к записи типа example. Затем (...).* преобразует это в столбцы, определенные в типе таблицы example

Вы можете использовать VALUES напрямую:

INSERT INTO example(a, b)
VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL);

Демо DBFiddle


Или просто бросьте один раз:

INSERT INTO example(a, b)
SELECT a::uuid, b::numeric
FROM (VALUES ('d853b5a8-d453-11e7-9296-cec278b6b50a', NULL), 
             ('bb53b5a8-d453-11e7-9296-cec278b6b50a',1) ) as data(a,b);

DBFiddle Demo2

Примечание, пожалуйста, всегда явно определяйте список столбцов.