Обчислені / обчислені / віртуальні / похідні стовпці в PostgreSQL


113

Чи підтримує PostgreSQL обчислені / обчислені стовпці, як MS SQL Server? Я нічого не можу знайти в документах, але оскільки ця функція входить у багато інших СУБД, я думав, що я можу щось пропустити.

Наприклад: http://msdn.microsoft.com/en-us/library/ms191250.aspx


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

Відповіді:


139

До Postgres 11 генерованих стовпців не підтримується - як визначено у стандарті SQL та реалізовано деякими RDBMS, включаючи 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));

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

Крім того, ви можете реалізувати подібну функціональність з VIEW, необов'язково поєднаним з індексами вираження. Потім SELECT *можна включити згенерований стовпець.

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

Матеріалізовані погляди - це тісно пов’язана концепція, реалізована після Постгресу 9.3 .
У попередніх версіях можна керувати МВ вручну.


Залежно від того, скільки даних ви завантажуєте одночасно .. тригер може різко уповільнити ситуацію. Можливо, замість цього можна розглянути оновлення.
сам урожай

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?
двтан

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



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    ;

Що саме PADB?
Герман

Аналітична база ParAccel - це стара, але приємна ... en.wikipedia.org/wiki/ParAccel
Wired604

Але як це стосується питання про Postgres? Звичайно, існує багато БД з підтримкою обчислених стовпців.
Герман

Ах вибачте, я не взяв час, щоб повернутися в контекст .... PADB заснований на поступі!
Wired604

-6

Легке рішення із обмеженням Check:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
Як це пов’язано з поняттям обчисленої колонки? Ви б хотіли пояснити?
Erwin Brandstetter

4
Погоджено, це не пов’язано безпосередньо. Але це заміна простого випадку, коли просто потрібно робити щось подібне field as 1 persisted.
cinereo

2
Опис справді був би приємним. Я думаю, що ця відповідь полягає в тому, що якщо обчислення можна виконати за замовчуванням, тоді ви можете використовувати за замовчуванням і обмеження для перевірки, щоб хто-небудь не міняв значення.
Росс Бредбері

@Ross Bradbury: Погодився, але це працює лише для вставки. Він не працюватиме, якби залежний стовпець оновлювався.
Стефан Штайгер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.