Преобразование целого числа в массив целых чисел (integer[]) в PostgreSQL с использованием UNION ALL

Вопросы и ответы

Я использую 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 будут в правильном формате. Если у вас будут дополнительные вопросы или понадобится помощь, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...