Вычисляемые / вычисляемые / виртуальные / производные столбцы в PostgreSQL

113

Поддерживает ли PostgreSQL вычисляемые / вычисляемые столбцы, такие как MS SQL Server? Я ничего не могу найти в документации, но, поскольку эта функция включена во многие другие СУБД, я подумал, что, возможно, мне что-то не хватает.

Например: http://msdn.microsoft.com/en-us/library/ms191250.aspx

Майк Чемберлен
источник
Используя латеральное выражение подзапроса (функция Postgres), вы можете легко добавить дополнительные столбцы в каждую строку.
Виктор

Ответы:

139

Сгенерированные столбцы до Postgres 11 не поддерживаются - как определено в стандарте SQL и реализовано некоторыми СУБД, включая DB2, MySQL и Oracle. И аналогичные «вычисляемые столбцы» SQL Server.

STOREDсгенерированные столбцы представлены в Postgres 12 . Тривиальный пример:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> скрипка здесь

VIRTUALсгенерированные столбцы могут появиться в одной из следующих итераций. (Пока нет в Postgres 13).

Связанный:


А пока вы можете имитировать VIRTUALсгенерированные столбцы с помощью функции, использующей нотацию атрибутов ( tbl.col), которая выглядит и работает так же, как виртуально сгенерированный столбец . Это немного странный синтаксис, который существует в Postgres по историческим причинам и подходит для случая. В этом связанном ответе есть примеры кода :

Однако выражение (похожее на столбец) в SELECT * FROM tbl. Вы всегда должны указывать это явно.

Также может поддерживаться соответствующий индекс выражения - при условии, что функция есть IMMUTABLE. Подобно:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

альтернативы

В качестве альтернативы вы можете реализовать аналогичные функции с помощью a VIEW, необязательно в сочетании с индексами выражений. Затем SELECT *можно включить сгенерированный столбец.

STOREDВычисляемые столбцы "Persisted" ( ) могут быть реализованы с помощью триггеров функционально идентичным образом.

Материализованные представления - это тесно связанная концепция, реализованная начиная с Postgres 9.3 .
В более ранних версиях можно было управлять MV вручную.

Эрвин Брандштеттер
источник
В зависимости от того, сколько данных вы загружаете одновременно, триггер может значительно замедлить работу. Возможно, вместо этого захотите рассмотреть обновления.
sam yi
1
Эти решения практически бесполезны (без огромных изменений кода в кодовой базе и без тестовых примеров) при переходе с Oracle на Postgres. Есть ли какие-нибудь решения с точки зрения миграции?
happybuddha
@happybuddha: Пожалуйста, задавайте свой вопрос как вопрос. Комментарии не к месту. Вы всегда можете добавить ссылку на этот вопрос для контекста (и добавить здесь комментарий, чтобы привлечь мое внимание, и ссылку на соответствующий вопрос).
Эрвин Брандштеттер,
4
Функционал находится в разработке: commitfest.postgresql.org/16/1443
r90t
1
@cryanbhu: Зависит от деталей вашей настройки и требований. Вы можете задать новый вопрос с необходимой информацией.
Эрвин Брандштеттер,
32

Да, ты можешь!! Решение должно быть простым, безопасным и производительным ...

Я новичок в postgresql, но, похоже, вы можете создавать вычисляемые столбцы, используя индекс выражения в сочетании с представлением (представление не является обязательным, но делает жизнь немного проще).

Предположим, мое вычисление таково md5(some_string_field), тогда я создаю индекс как:

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

Теперь любые MD5(some_string_field)выполняемые запросы будут использовать индекс, а не вычислять его с нуля. Например:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

Вы можете проверить это с помощью объяснения .

Однако на этом этапе вы полагаетесь на пользователей таблицы, которые точно знают, как построить столбец. Чтобы упростить жизнь, вы можете создать VIEWрасширенную версию исходной таблицы, добавив вычисленное значение в качестве нового столбца:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

Теперь любые запросы, которые используются some_table_augmented, можно будет использовать, some_string_field_md5не беспокоясь о том, как это работает ... они просто получают хорошую производительность. Представление не копирует данные из исходной таблицы, поэтому оно хорошо как с точки зрения памяти, так и с точки зрения производительности. Однако обратите внимание, что вы не можете обновлять / вставлять в представление, только в исходную таблицу, но если вы действительно хотите, я считаю, что вы можете перенаправить вставки и обновления в исходную таблицу с помощью правил (я мог ошибаться в этом последнем пункте, поскольку Сам никогда не пробовал).

Изменить: кажется, что если запрос включает конкурирующие индексы, механизм планировщика может иногда вообще не использовать индекс-выражение. Выбор, похоже, зависит от данных.

дан-ман
источник
1
Не могли бы вы объяснить или привести пример if the query involves competing indices?
dvtan
17

Один из способов сделать это - использовать триггер!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

Триггер срабатывает перед обновлением или вставкой строки. Он изменяет поле, которое мы хотим вычислить для NEWзаписи, а затем возвращает эту запись.

Элмер
источник
Когда срабатывает спусковой крючок? Я выполнил вышеуказанное и сделал это, insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;и оно только что вернулось: 1 2 и 4 8
happybuddha
2
попробуйте insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;значение twoстолбца будет рассчитано автоматически!
Элмер,
8

PostgreSQL 12 поддерживает сгенерированные столбцы:

Вышел PostgreSQL 12 Beta 1!

Сгенерированные столбцы

PostgreSQL 12 позволяет создавать сгенерированные столбцы, которые вычисляют свои значения с помощью выражения, использующего содержимое других столбцов. Эта функция предоставляет сохраненные сгенерированные столбцы, которые вычисляются при вставках и обновлениях и сохраняются на диске. Виртуально сгенерированные столбцы, которые вычисляются только тогда, когда столбец считывается как часть запроса, еще не реализованы.


Сгенерированные столбцы

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

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> демо скрипта

Лукаш Шозда
источник
Статья в блоге: 2ndquadrant.com/en/blog/generated-columns-in-postgresql-12
Christophe
1

Не уверен, что Вы имеете в виду именно это, но Posgres обычно поддерживает "фиктивный" синтаксис ETL. Я создал один пустой столбец в таблице, а затем мне нужно было заполнить его расчетными записями в зависимости от значений в строке.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. Это так глупо, что я подозреваю, что это не то, что Вы ищете.
  2. Очевидно, что это не динамично, вы запускаете его один раз. Но нет никаких препятствий, чтобы попасть в курок.
Лобо
источник
0

У меня есть код, который работает, и я использую термин рассчитанный, я не использую чистый postgresSQL, хотя мы работаем на PADB

вот как это используется

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;
Проводной604
источник
Что такое PADB?
Gherman
Аналитическая база данных ParAccel старая, но красивая ... en.wikipedia.org/wiki/ParAccel
Wired604,
Но как это связано с вопросом о Postgres? Конечно, существует множество БД с поддержкой вычисляемых столбцов.
Gherman
ах, извините, я не нашел времени, чтобы вернуться в контекст .... PADB основан на postgress!
Wired604
-6

Легкое решение с ограничением Check:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
cinereo
источник
6
Как это связано с концепцией вычисляемого столбца? Не могли бы вы объяснить?
Эрвин Брандштеттер
4
Согласен, напрямую не связано. Но это замена простого случая, когда вам просто нужно сделать что-то вроде field as 1 persisted.
cinereo 05
2
Описание действительно было бы неплохо. Я думаю, что этот ответ заключается в том, что если вычисление может быть выполнено с предложением по умолчанию, вы можете использовать ограничение по умолчанию и ограничение проверки, чтобы никто не мог изменить значение.
Росс Брэдбери
@ Росс Брэдбери: Согласен, но это работает только для вставки. Это не сработало бы, если бы зависимый столбец обновился.
Stefan Steiger