Как выбрать только * столбцы * с более чем одним отдельным значением? - PullRequest
0 голосов
/ 04 мая 2020

SELECT DISTINCT … удаляет повторяющиеся строки. Есть ли способ удалить дубликаты столбцов, , то есть столбцы, где все значения одинаковы? Я просматриваю устаревшую схему для «отличительных особенностей» некоторых строк, так что это было бы очень полезно. Если это облегчает задачу, все столбцы являются простыми типами, такими как INT, TEXT и TIMESTAMP. По сути, при наличии такой таблицы:

CREATE TEMPORARY TABLE column_test
(
    foo TEXT,
    bar INT,
    baz BOOLEAN,
    bat TIMESTAMP WITH TIME ZONE
);

INSERT INTO column_test (
    foo, bar, baz, bat
) VALUES
    ('lorem ipsum', 1, TRUE, '2000-01-01 UTC'),
    ('lorem ipsum', 2, TRUE, '2000-01-01 UTC'),
    ('other', 3, TRUE, '2000-01-01 UTC');

можно ли написать запрос, который будет выбирать только столбцы foo и bar, поскольку это единственные столбцы с более чем одним значением? Примерно так:

SELECT columns_with_more_than_one_value(*) FROM column_test;
foo           bar
'lorem ipsum' 1
'lorem ipsum' 2
'other'       3

Полагаю, одним из способов будет SELECT *, транспонировать результат, удалить все строки, в которых все значения одинаковы, а затем снова транспонировать, но это будет очень сложный, и я не знаю, как сохранить исходные имена столбцов в результате.

1 Ответ

1 голос
/ 04 мая 2020

В принципе вы не можете выбрать неизвестные столбцы из таблицы. Результат запроса должен иметь структуру, определенную до его выполнения. Что вы можете сделать, это создать (временное) представление, которое содержит ожидаемые столбцы. Приведенная ниже функция выполняет работу, широко используя dynamici c SQL. Первый аргумент функции - это имя таблицы, второй - имя создаваемого временного представления.

create or replace function create_view_with_distinct_columns(text, text)
returns void language plpgsql as $$
declare
    col text;
    ct int;
    list text = '';
begin
    for col in 
        execute format('
            select attname
            from pg_attribute
            where attrelid = %s
            and attnum > 0',
            $1::regclass::oid)
    loop
        execute format('
            select count(distinct %I)
            from %I',
            col, $1)
        into ct;
        if ct > 1 then
            list:= format('%s%s,', list, col);
        end if;
    end loop;
    execute format('
        create temp view %I as
        select %s
        from %I',
        $2, left(list, -1), $1);
end $$;

Использование:

select create_view_with_distinct_columns('column_test', 'column_view');

select * from column_view;

     foo     | bar
-------------+-----
 lorem ipsum |   1
 lorem ipsum |   2
 other       |   3
(3 rows)    

Db <> скрипка.

...