Я использую PostgreSQL и у меня есть оператор SELECT по нескольким таблицам
CREATE OR REPLACE VIEW group.all
AS
SELECT 'gmail'::text AS main_source,
gmail.id,
gmail.from,
gmail.to,
gmail.user_id
FROM first_group.gmail
UNION ALL
SELECT 'yahoo'::text AS main_source,
yahoo.id,
yahoo.from,
yahoo.to,
yahoo.user_id
FROM second_group.yahoo
UNION ALL
SELECT 'outlook'::text AS main_source,
outlook.id,
outlook.from,
outlook.to,
NULL::integer AS user_id
FROM third_group.outlook
Для значения NULL я теперь хочу изменить его на participant_ids, которые имеют тип данных integer[], в то время как для всех источников user_id имеет тип данных integer.
Я пробовал кастинг:
SELECT 'outlook'::text AS main_source,
outlook.id,
outlook.from,
outlook.to,
outlook.participant_ids::integer AS user_id
FROM third_group.outlook
Но получил эту ошибку ERROR: UNION types integer and integer[] cannot be matched
Я также пробовал этот синтаксис ARRAY[outlook.participant_ids]::integer
, но получил ошибку.
Я также пытался изменить тип данных столбца для всех источников, используя эту команду и изменяя её для каждого источника.
ALTER TABLE first_group.gmail
ALTER COLUMN user_id TYPE integer[];
ALTER TABLE second_group.yahoo
ALTER COLUMN user_id TYPE integer[];
ALTER TABLE third_group.outlook
ALTER COLUMN user_id TYPE integer[];
Но получил эту ошибку ERROR: column "user_id" cannot be cast automatically to type integer[] HINT: You might need to specify "USING user_id::integer[]".
Так была создана таблица.
CREATE TABLE third_group.outlook(
id integer NOT NULL,
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
participants_ids integer[]
)
Такая же таблица была создана для first_group и second_group.
Есть ли способ преобразовать тип данных integer в integer[]? Или есть ли способ изменить тип данных столбца с integer на integer[]?
Вы не можете преобразовать integer в массив или обратно. Вы можете только обернуть integer в массив или получить доступ к элементу массива. Вы, похоже, ищете
SELECT 'gmail'::text AS main_source,
gmail.id,
gmail.from,
gmail.to,
ARRAY[gmail.user_id] AS user_ids
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FROM first_group.gmail
UNION ALL
SELECT 'yahoo'::text AS main_source,
yahoo.id,
yahoo.from,
yahoo.to,
ARRAY[yahoo.user_id] AS user_ids
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FROM second_group.yahoo
UNION ALL
SELECT 'outlook'::text AS main_source,
outlook.id,
outlook.from,
outlook.to,
outlook.participant_ids AS user_ids
FROM third_group.outlook
Запрос Bergi работает с типами данных, которые вы указали: integer
для user_id
и integer[]
для participant_ids
. (Вы не объявили правильно.)
Изменение типа столбца с integer
на integer[]
работает так:
ALTER TABLE first_group.gmail
ALTER COLUMN user_id TYPE integer[] USING ARRAY[user_id];
Так или иначе, вам нужен Конструктор массива.
Обратите внимание, что это создаст {null}
(массив с одним элементом null) для null
входа. Если вы хотите простой null
вместо этого:
ALTER TABLE first_group.gmail
ALTER COLUMN user_id TYPE integer[] USING NULLIF(ARRAY[user_id], '{null}');
Ответ
Ваша проблема связана с несоответствием типов данных в объединении запросов (UNION ALL) в PostgreSQL. Для того, чтобы у вас все правильно работало, я объясню, как вы можете привести ваши поля к нужным типам данных.
Решение проблемы с union all
Как указано в вашем вопросе, вы хотите, чтобы user_id
у всех источников был типом integer[]
, тогда как в ваших таблицах first_group.gmail
и second_group.yahoo
user_id
имеет тип integer
. Чтобы объединить результаты без ошибок, вы можете обернуть user_id
в массивы:
CREATE OR REPLACE VIEW group.all AS
SELECT 'gmail'::text AS main_source,
gmail.id,
gmail.from,
gmail.to,
ARRAY[gmail.user_id] AS user_ids -- оборачиваем в массив
FROM first_group.gmail
UNION ALL
SELECT 'yahoo'::text AS main_source,
yahoo.id,
yahoo.from,
yahoo.to,
ARRAY[yahoo.user_id] AS user_ids -- оборачиваем в массив
FROM second_group.yahoo
UNION ALL
SELECT 'outlook'::text AS main_source,
outlook.id,
outlook.from,
outlook.to,
outlook.participant_ids AS user_ids -- здесь уже массив
FROM third_group.outlook;
Этот код создаёт представление, в котором результат user_id
из первых двух запросов будет представленный как массив (integer[]
), что соответствует типу данных в третьем запросе.
Преобразование типа столбца в таблицах
Если вы хотите изменить тип столбца user_id
в таблицах first_group.gmail
и second_group.yahoo
на integer[]
, это нужно делать осторожно, чтобы не потерять данные. Вы можете использовать следующее:
ALTER TABLE first_group.gmail
ALTER COLUMN user_id TYPE integer[] USING ARRAY[user_id];
ALTER TABLE second_group.yahoo
ALTER COLUMN user_id TYPE integer[] USING ARRAY[user_id];
Этот SQL-запрос изменяет тип столбца user_id
на integer[]
, где он будет обёрнут в массив из текущего значения.
Обработка NULL
значений
Если вы хотите, чтобы, при преобразовании NULL
значения, вы получали NULL
вместо массива с одним NULL
элементом, используйте следующий подход:
ALTER TABLE first_group.gmail
ALTER COLUMN user_id TYPE integer[] USING NULLIF(ARRAY[user_id], '{null}');
ALTER TABLE second_group.yahoo
ALTER COLUMN user_id TYPE integer[] USING NULLIF(ARRAY[user_id], '{null}');
Заключение
Теперь, после того как вы примените указанное решение и выполните модификации типов данных, ваш запрос UNION ALL
будет работать без ошибок, и все значения user_id
будут в правильном формате. Если у вас будут дополнительные вопросы или понадобится помощь, не стесняйтесь обращаться!