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

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

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

Ответы [ 7 ]

95 голосов
/ 24 ноября 2011

До 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
);

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

VIRTUAL сгенерированные столбцы могут идти со следующей итерацией. Связанный:

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

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

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

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

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

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

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

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

25 голосов
/ 22 марта 2017

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

Я новичок в 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, не беспокоясь о том, как это работает .. они просто получают хорошую производительность.Представление не копирует какие-либо данные из исходной таблицы, поэтому оно хорошо как с точки зрения памяти, так и с точки зрения производительности.Однако обратите внимание, что вы не можете обновлять / вставлять в представление, только в исходную таблицу, но если вы действительно этого хотите, я думаю, вы можете перенаправить вставки и обновления в исходную таблицу, используя rules (я мог бынеправильно в последнем пункте, поскольку я никогда не пробовал сам).

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

12 голосов
/ 13 декабря 2015

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

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, а затем возвращает эту запись.

4 голосов
/ 23 мая 2019

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 <> демонстрация скрипки

0 голосов
/ 25 октября 2018

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

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

У меня есть код, который работает, и я использую вычисленный термин, я не на 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    ;
0 голосов
/ 17 августа 2013

Легкое решение с проверочным ограничением:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...