PostgreSQL'de hesaplanmış / hesaplanmış / sanal / türetilmiş sütunlar


113

PostgreSQL, MS SQL Server gibi hesaplanan / hesaplanan sütunları destekler mi? Dokümanlarda hiçbir şey bulamıyorum, ancak bu özellik diğer birçok DBMS'de bulunduğundan, bir şeyleri kaçırıyor olabileceğimi düşündüm.

Örneğin: http://msdn.microsoft.com/en-us/library/ms191250.aspx


Yanal alt sorgu ifadesini (Postgres özelliği) kullanarak her satıra kolayca daha fazla sütun ekleyebilirsiniz.
Victor

Yanıtlar:


139

Postgres'e kadar 11 oluşturulan sütun desteklenmez - SQL standardında tanımlandığı gibi ve DB2, MySQL ve Oracle dahil olmak üzere bazı RDBMS tarafından uygulanır. Ne de SQL Server'ın benzer "hesaplanan sütunları" .

STOREDoluşturulan sütunlar Postgres 12 ile tanıtılır . Önemsiz örnek:

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

db <> burada fiddle

VIRTUALoluşturulan sütunlar sonraki yinelemelerden biriyle gelebilir. (Henüz Postgres 13'te değil).

İlişkili:


O zamana kadar , VIRTUALoluşturulan sütunları öznitelik notasyonu ( ) kullanarak bir işlevle taklit edebilirsiniz .tbl.col sanal olarak oluşturulmuş bir sütun gibi görünen ve çalışan . Bu, Postgres'te tarihsel nedenlerle var olan ve duruma uyan bir tür sözdizimi tuhaflığıdır. Bu ilgili yanıtın kod örnekleri vardır :

İfade (sütun gibi görünen) bir SELECT * FROM tbl . Her zaman açıkça listelemelisiniz.

Eşleşen bir ifade indeksi ile de desteklenebilir - işlevin olması şartıylaIMMUTABLE . Sevmek:

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

Alternatifler

Alternatif olarak, benzer işlevselliği bir VIEW isteğe bağlı olarak ifade dizinleri ile birleştirilen . SonraSELECT * oluşturulan sütunu dahil edebilirsiniz.

"Kalıcı" ( STORED) hesaplanan sütunlar, işlevsel olarak aynı şekilde tetikleyicilerle uygulanabilir .

Gerçekleştirilmiş görünümler , Postgres 9.3'ten beri uygulanan yakından ilişkili bir kavramdır .
Önceki sürümlerde MV'ler manuel olarak yönetilebilir.


Tek seferde ne kadar veri yüklediğinize bağlı olarak .. tetikleme işleri büyük ölçüde yavaşlatabilir. Bunun yerine güncellemeleri değerlendirmek isteyebilirsiniz.
sam yi

1
Bu çözümler, oracle'dan postgres'e geçerken oldukça faydasızdır (test durumları olmayan bir kod tabanında büyük kod değişiklikleri olmadan). Göç açısından herhangi bir çözüm var mı?
happybuddha

@happybuddha: Lütfen sorunuzu soru olarak sorun. Yorumlar yer değil. Bağlam için her zaman bu soruya bağlantı verebilirsiniz (ve dikkatimi çekmek ve ilgili soruya bağlantı vermek için buraya bir yorum ekleyebilirsiniz).
Erwin Brandstetter

4
İşlevsellik şu anda geliştiriliyor: commitfest.postgresql.org/16/1443
r90t

1
@cryanbhu: Kurulumunuzun ve gereksinimlerinizin ayrıntılarına bağlıdır. Gerekli bilgilerle yeni bir soru sorabilirsiniz.
Erwin Brandstetter

32

Evet yapabilirsin!! Çözüm kolay, güvenli ve başarılı olmalı ...

Postgresql'de yeniyim, ancak görünen o ki bir görünümle eşleştirilmiş bir ifade dizini kullanarak hesaplanmış sütunlar oluşturabilirsiniz (görünüm isteğe bağlıdır, ancak hayatı biraz daha kolaylaştırır).

Hesaplamamın şöyle olduğunu varsayalım md5(some_string_field), sonra dizini şu şekilde oluşturuyorum:

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

Şimdi, işe yarayan tüm sorgular MD5(some_string_field), dizini sıfırdan hesaplamak yerine kullanacaktır. Örneğin:

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

Bunu açıklayarak kontrol edebilirsiniz .

Ancak bu noktada, tablonun kullanıcılarının tam olarak sütunun nasıl oluşturulacağını bilmelerine güveniyorsunuz. Hayatı kolaylaştırmak için, VIEWhesaplanan değeri yeni bir sütun olarak ekleyerek, orijinal tablonun artırılmış bir sürümüne bir üstüne oluşturabilirsin :

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

Artık kullanan herhangi bir sorgu some_table_augmented, some_string_field_md5nasıl çalıştığı konusunda endişelenmeden kullanabilecek ... sadece iyi performans elde ediyorlar. Görünüm, orijinal tablodaki herhangi bir veriyi kopyalamıyor, bu nedenle performans açısından olduğu kadar bellek açısından da iyidir. Ancak bir görünüme güncelleme / ekleme yapamayacağınızı, yalnızca kaynak tabloya ekleyemeyeceğinizi unutmayın, ancak gerçekten istiyorsanız, ekleri ve güncellemeleri kuralları kullanarak kaynak tabloya yeniden yönlendirebileceğinize inanıyorum (bu son noktada yanılmış olabilirim. Kendim hiç denemedim).

Düzenleme: Sorgu rakip endeksleri içeriyorsa, planlayıcı motoru bazen ifade-dizinini hiç kullanmayabilir. Seçim veriye bağlı görünüyor.


1
Açıklayabilir misiniz veya bir örnek verebilir misiniz if the query involves competing indices?
dvtan

17

Bunu yapmanın bir yolu tetik kullanmaktır!

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();

Tetikleyici, satır güncellenmeden veya eklenmeden önce tetiklenir. NEWKaydı hesaplamak istediğimiz alanı değiştirir ve ardından o kaydı döndürür.


Tetik ne zaman keskin bir şekilde ateşleniyor? Yukarıdakileri çalıştırdım ve bunu yaptım insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;ve geri döndü: 1 2 ve 4 8
happybuddha

2
deneyin sütunun insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;değeri otomatik twoolarak hesaplanacaktır!
Elmer

8

PostgreSQL 12, oluşturulan sütunları destekler:

PostgreSQL 12 Beta 1 Yayınlandı!

Oluşturulan Sütunlar

PostgreSQL 12, değerlerini diğer sütunların içeriğini kullanan bir ifade ile hesaplayan oluşturulmuş sütunların oluşturulmasına izin verir. Bu özellik, eklerde ve güncellemelerde hesaplanan ve diske kaydedilen depolanan, oluşturulan sütunlar sağlar. Yalnızca bir sütun bir sorgunun parçası olarak okunduğunda hesaplanan sanal olarak oluşturulan sütunlar henüz uygulanmamaktadır.


Oluşturulan Sütunlar

Oluşturulan sütun, her zaman diğer sütunlardan hesaplanan özel bir sütundur. Bu nedenle, tablolar için görünüm ne ise sütunlar içindir.

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

db <> fiddle demosu



1

Peki, demek istediğiniz bu mu emin değilim ama Posgres normalde "kukla" ETL sözdizimini destekler. Tabloda boş bir sütun oluşturdum ve ardından satırdaki değerlere bağlı olarak hesaplanan kayıtlarla doldurmam gerekiyordu.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. O kadar aptalca ki, aradığınızın bu olmadığından şüpheleniyorum.
  2. Açıkçası dinamik değil, bir kez çalıştırıyorsun. Ama onu tetiklemesine engel yok.

0

Çalışan ve hesaplanan terimi kullanan bir kodum var, PADB'de çalıştırdığımız için postgresSQL'de değilim

işte nasıl kullanıldığı

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 tam olarak nedir?
Gherman

ParAccel Analitik Veritabanı eski ama güzel ... en.wikipedia.org/wiki/ParAccel
Wired604

Peki Postgres ile ilgili bir soru ile nasıl bağlantılı? Elbette, hesaplanan sütunların desteğine sahip çok sayıda DB vardır.
Gherman

ah özür dilerim, içeriğe dönmek için zaman ayırmadım .... PADB, postgress temellidir!
Wired604

-6

Check kısıtlaması olan hafif bir çözüm:

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

6
Bu, hesaplanmış bir sütun kavramıyla nasıl ilişkilidir? Açıklamak ister misin?
Erwin Brandstetter

4
Kabul edildi, doğrudan ilgili değil. Ancak, bunun gibi bir şey yapmanız gerektiğinde basit bir durumun yerine geçer field as 1 persisted.
cinereo

2
Bir açıklama gerçekten güzel olurdu. Sanırım bu yanıt, hesaplama varsayılan cümle ile yapılabiliyorsa, herhangi birinin değeri değiştirmesini önlemek için bir varsayılan ve bir kontrol kısıtlaması kullanabilirsiniz.
Ross Bradbury

@Ross Bradbury: Kabul edildi, ancak bu yalnızca giriş için geçerli. Bağımlı bir sütun güncellenirse çalışmaz.
Stefan Steiger
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.