PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Gambaran Umum Kolom yang Dihasilkan untuk PostgreSQL

PostgreSQL 12 hadir dengan fitur baru yang hebat, Kolom yang Dihasilkan. Fungsionalitasnya bukanlah sesuatu yang baru, tetapi standarisasi, kemudahan penggunaan, aksesibilitas, dan kinerja telah ditingkatkan dalam versi baru ini.

A Generated Column adalah kolom khusus dalam tabel yang berisi data yang dihasilkan secara otomatis dari data lain di dalam baris. Konten kolom yang dihasilkan secara otomatis diisi dan diperbarui setiap kali data sumber, seperti kolom lain dalam baris, diubah sendiri.

Kolom yang Dihasilkan di PostgreSQL 12+

Dalam PostgreSQL versi terbaru, kolom yang dihasilkan adalah fitur bawaan yang memungkinkan pernyataan CREATE TABLE atau ALTER TABLE untuk menambahkan kolom di mana konten secara otomatis 'dihasilkan' sebagai hasil dari ekspresi. Ekspresi ini dapat berupa operasi matematika sederhana dari kolom lain, atau fungsi yang lebih maju yang tidak dapat diubah. Beberapa manfaat dari mengimplementasikan kolom yang dihasilkan ke dalam desain database meliputi:

  • Kemampuan untuk menambahkan kolom ke tabel yang berisi data yang dihitung tanpa perlu memperbarui kode aplikasi untuk menghasilkan data untuk kemudian memasukkannya ke dalam operasi INSERT dan UPDATE.
  • Mengurangi waktu pemrosesan pada pernyataan SELECT yang sangat sering yang akan memproses data dengan cepat. Karena pemrosesan data dilakukan pada saat INSERT atau UPDATE, data dihasilkan satu kali dan pernyataan SELECT hanya perlu mengambil data. Dalam lingkungan membaca yang berat, ini mungkin lebih baik, selama penyimpanan data ekstra yang digunakan dapat diterima.
  • Karena kolom yang dihasilkan diperbarui secara otomatis ketika data sumber itu sendiri diperbarui, menambahkan kolom yang dihasilkan akan menambahkan jaminan yang diasumsikan bahwa data di kolom yang dihasilkan selalu benar.

Di PostgreSQL 12, hanya jenis kolom yang dihasilkan 'DISIMPAN' yang tersedia. Dalam sistem database lain, kolom yang dihasilkan dengan tipe 'VIRTUAL' tersedia, yang bertindak lebih seperti tampilan di mana hasilnya dihitung dengan cepat saat data diambil. Karena fungsinya sangat mirip dengan tampilan, dan hanya menulis operasi ke dalam pernyataan pilihan, fungsi tersebut tidak begitu bermanfaat seperti fungsi 'DISIMPAN' yang dibahas di sini, tetapi ada kemungkinan versi mendatang akan menyertakan fitur tersebut.

Membuat Tabel Dengan Kolom yang Dihasilkan dilakukan saat mendefinisikan kolom itu sendiri. Dalam contoh ini, kolom yang dihasilkan adalah 'keuntungan', dan secara otomatis dihasilkan dengan mengurangkan harga_pembelian dari kolom harga_penjualan, lalu dikalikan dengan kolom jumlah_penjualan.

CREATE TABLE public.transactions (

    transactions_sid serial primary key,

    transaction_date timestamp with time zone DEFAULT now() NOT NULL,

    product_name character varying NOT NULL,

    purchase_price double precision NOT NULL,

    sale_price double precision NOT NULL,

    quantity_sold integer NOT NULL,

    profit double precision NOT NULL GENERATED ALWAYS AS  ((sale_price - purchase_price) * quantity_sold) STORED

);

Dalam contoh ini, tabel 'transaksi' dibuat untuk melacak beberapa transaksi dasar dan keuntungan dari kedai kopi imajiner. Memasukkan data ke dalam tabel ini akan menampilkan beberapa hasil langsung.

​severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('House Blend Coffee', 5, 11.99, 1);

severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('French Roast Coffee', 6, 12.99, 4);

severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('BULK: House Blend Coffee, 10LB', 40, 100, 6);



severalnines=# SELECT * FROM public.transactions;

 transactions_sid |       transaction_date |          product_name | purchase_price | sale_price | quantity_sold | profit

------------------+-------------------------------+--------------------------------+----------------+------------+---------------+--------

                1 | 2020-02-28 04:50:06.626371+00 | House Blend Coffee             | 5 | 11.99 | 1 | 6.99

                2 | 2020-02-28 04:50:53.313572+00 | French Roast Coffee            | 6 | 12.99 | 4 | 27.96

                3 | 2020-02-28 04:51:08.531875+00 | BULK: House Blend Coffee, 10LB |             40 | 100 | 6 | 360

Saat memperbarui baris, kolom yang dihasilkan akan diperbarui secara otomatis:

​severalnines=# UPDATE public.transactions SET sale_price = 95 WHERE transactions_sid = 3;

UPDATE 1



severalnines=# SELECT * FROM public.transactions WHERE transactions_sid = 3;

 transactions_sid |       transaction_date |          product_name | purchase_price | sale_price | quantity_sold | profit

------------------+-------------------------------+--------------------------------+----------------+------------+---------------+--------

                3 | 2020-02-28 05:55:11.233077+00 | BULK: House Blend Coffee, 10LB |             40 | 95 | 6 | 330

Ini akan memastikan bahwa kolom yang dihasilkan selalu benar, tanpa logika tambahan yang diperlukan di sisi aplikasi.

CATATAN:Kolom yang dihasilkan tidak dapat DIMASUKKAN ke dalam atau DIPERBARUI secara langsung, dan setiap upaya untuk melakukannya akan menghasilkan KESALAHAN:

severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold, profit) VALUES ('BULK: House Blend Coffee, 10LB', 40, 95, 1, 95);

ERROR:  cannot insert into column "profit"

DETAIL:  Column "profit" is a generated column.



severalnines=# UPDATE public.transactions SET profit = 330 WHERE transactions_sid = 3;

ERROR:  column "profit" can only be updated to DEFAULT

DETAIL:  Column "profit" is a generated column.

Kolom yang Dihasilkan pada PostgreSQL 11 dan Sebelumnya

Meskipun kolom yang dibuat di dalamnya baru untuk PostgreSQL versi 12, secara fungsional masih dapat dicapai di versi sebelumnya, hanya perlu sedikit lebih banyak pengaturan dengan prosedur dan pemicu yang tersimpan. Namun, bahkan dengan kemampuan untuk mengimplementasikannya pada versi yang lebih lama, selain fungsionalitas tambahan yang dapat bermanfaat, kepatuhan input data yang ketat lebih sulit dicapai, dan bergantung pada fitur PL/pgSQL dan kecerdikan pemrograman.

BONUS:Contoh di bawah ini juga akan berfungsi pada PostgreSQL 12+, jadi jika fungsionalitas tambahan dengan kombo fungsi/pemicu diperlukan atau diinginkan dalam versi yang lebih baru, opsi ini merupakan fallback yang valid dan tidak terbatas pada hanya versi yang lebih lama dari 12. 

Meskipun ini adalah cara untuk melakukannya di PostgreSQL versi sebelumnya, ada beberapa manfaat tambahan dari metode ini: 

  • Karena meniru kolom yang dihasilkan menggunakan fungsi, perhitungan yang lebih kompleks dapat digunakan. Kolom yang Dihasilkan dalam versi 12 memerlukan operasi yang TIDAK DAPAT DIUBAH, tetapi opsi pemicu / fungsi dapat menggunakan jenis fungsi STABIL atau VOLATILE dengan kemungkinan yang lebih besar dan kemungkinan kinerja yang lebih rendah.
  • Menggunakan fungsi yang memiliki opsi untuk menjadi STABLE atau VOLATILE juga membuka kemungkinan untuk MEMPERBARUI kolom tambahan, MEMPERBARUI tabel lain, atau bahkan membuat data baru melalui INSERTS ke tabel lain. (Namun, meskipun opsi pemicu/fungsi ini jauh lebih fleksibel, bukan berarti "Kolom yang Dihasilkan" sebenarnya tidak ada, karena ia melakukan apa yang diiklankan dengan kinerja dan efisiensi yang lebih besar.)

Dalam contoh ini, pemicu / fungsi diatur untuk meniru fungsionalitas kolom yang dihasilkan PostgreSQL 12+, bersama dengan dua bagian yang memunculkan pengecualian jika INSERT atau UPDATE mencoba mengubah kolom yang dihasilkan . Ini dapat dihilangkan, tetapi jika dihilangkan, pengecualian tidak akan dimunculkan, dan data aktual DIMASUKKAN atau DIPERBARUI akan diam-diam dibuang, yang umumnya tidak direkomendasikan.

Pemicu itu sendiri diatur untuk dijalankan SEBELUM, yang berarti pemrosesan terjadi sebelum penyisipan yang sebenarnya terjadi, dan memerlukan RETURN of NEW, yaitu RECORD yang dimodifikasi untuk memuat nilai kolom yang dihasilkan baru. Contoh khusus ini ditulis untuk dijalankan pada PostgreSQL versi 11.

CREATE TABLE public.transactions (

    transactions_sid serial primary key,

    transaction_date timestamp with time zone DEFAULT now() NOT NULL,

    product_name character varying NOT NULL,

    purchase_price double precision NOT NULL,

    sale_price double precision NOT NULL,

    quantity_sold integer NOT NULL,

    profit double precision NOT NULL

);



CREATE OR REPLACE FUNCTION public.generated_column_function()

 RETURNS trigger

 LANGUAGE plpgsql

 IMMUTABLE

AS $function$

BEGIN



    -- This statement mimics the ERROR on built in generated columns to refuse INSERTS on the column and return an ERROR.

    IF (TG_OP = 'INSERT') THEN

        IF (NEW.profit IS NOT NULL) THEN

            RAISE EXCEPTION 'ERROR:  cannot insert into column "profit"' USING DETAIL = 'Column "profit" is a generated column.';

        END IF;

    END IF;



    -- This statement mimics the ERROR on built in generated columns to refuse UPDATES on the column and return an ERROR.

    IF (TG_OP = 'UPDATE') THEN

        -- Below, IS DISTINCT FROM is used because it treats nulls like an ordinary value. 

        IF (NEW.profit::VARCHAR IS DISTINCT FROM OLD.profit::VARCHAR) THEN

            RAISE EXCEPTION 'ERROR:  cannot update column "profit"' USING DETAIL = 'Column "profit" is a generated column.';

        END IF;

    END IF;



    NEW.profit := ((NEW.sale_price - NEW.purchase_price) * NEW.quantity_sold);

    RETURN NEW;



END;

$function$;




CREATE TRIGGER generated_column_trigger BEFORE INSERT OR UPDATE ON public.transactions FOR EACH ROW EXECUTE PROCEDURE public.generated_column_function();

CATATAN:Pastikan fungsi memiliki izin/kepemilikan yang benar untuk dijalankan oleh pengguna aplikasi yang diinginkan.

Seperti yang terlihat pada contoh sebelumnya, hasilnya sama di versi sebelumnya dengan solusi fungsi / pemicu:

​severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('House Blend Coffee', 5, 11.99, 1);

severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('French Roast Coffee', 6, 12.99, 4);

severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold) VALUES ('BULK: House Blend Coffee, 10LB', 40, 100, 6);



severalnines=# SELECT * FROM public.transactions;

 transactions_sid |       transaction_date |          product_name | purchase_price | sale_price | quantity_sold | profit

------------------+-------------------------------+--------------------------------+----------------+------------+---------------+--------

                1 | 2020-02-28 00:35:14.855511-07 | House Blend Coffee             | 5 | 11.99 | 1 | 6.99

                2 | 2020-02-28 00:35:21.764449-07 | French Roast Coffee            | 6 | 12.99 | 4 | 27.96

                3 | 2020-02-28 00:35:27.708761-07 | BULK: House Blend Coffee, 10LB |             40 | 100 | 6 | 360

Memperbarui data akan serupa.

​severalnines=# UPDATE public.transactions SET sale_price = 95 WHERE transactions_sid = 3;

UPDATE 1



severalnines=# SELECT * FROM public.transactions WHERE transactions_sid = 3;

 transactions_sid |       transaction_date |          product_name | purchase_price | sale_price | quantity_sold | profit

------------------+-------------------------------+--------------------------------+----------------+------------+---------------+--------

                3 | 2020-02-28 00:48:52.464344-07 | BULK: House Blend Coffee, 10LB |             40 | 95 | 6 | 330

Terakhir, mencoba INSERT ke, atau UPDATE kolom khusus itu sendiri akan menghasilkan ERROR:

​severalnines=# INSERT INTO public.transactions (product_name, purchase_price, sale_price, quantity_sold, profit) VALUES ('BULK: House Blend Coffee, 10LB', 40, 95, 1, 95);

ERROR:  ERROR: cannot insert into column "profit"

DETAIL:  Column "profit" is a generated column.

CONTEXT:  PL/pgSQL function generated_column_function() line 7 at RAISE



severalnines=# UPDATE public.transactions SET profit = 3030 WHERE transactions_sid = 3;

ERROR:  ERROR: cannot update column "profit"

DETAIL:  Column "profit" is a generated column.

CONTEXT:  PL/pgSQL function generated_column_function() line 15 at RAISE

Dalam contoh ini, tindakannya berbeda dari penyiapan kolom pertama yang dibuat dalam beberapa cara yang harus diperhatikan:

  • Jika 'kolom yang dihasilkan' dicoba untuk diperbarui tetapi tidak ada baris yang ditemukan untuk diperbarui, itu akan mengembalikan keberhasilan dengan hasil “PERBARUI 0”, sedangkan Kolom yang Dihasilkan sebenarnya di versi 12 akan tetap mengembalikan KESALAHAN, meskipun tidak ada baris yang ditemukan untuk UPDATE.
  • Saat mencoba memperbarui kolom keuntungan, yang 'harus' selalu mengembalikan KESALAHAN, jika nilai yang ditentukan sama dengan nilai yang 'dihasilkan' dengan benar, itu akan berhasil. Namun, pada akhirnya data benar, jika diinginkan untuk mengembalikan KESALAHAN jika kolom ditentukan.

Dokumentasi dan Komunitas PostgreSQL

Dokumentasi resmi untuk Kolom yang Dihasilkan PostgreSQL terletak di Situs Web PostgreSQL resmi. Periksa kembali saat versi utama PostgreSQL baru dirilis untuk menemukan fitur baru saat fitur tersebut muncul.

Meskipun kolom yang dihasilkan di PostgreSQL 12 cukup mudah, menerapkan fungsionalitas serupa di versi sebelumnya berpotensi menjadi jauh lebih rumit. Komunitas PostgreSQL adalah komunitas yang sangat aktif, masif, di seluruh dunia, dan multibahasa yang didedikasikan untuk membantu orang-orang dari berbagai tingkat pengalaman PostgreSQL memecahkan masalah dan menciptakan solusi baru seperti ini.

  • IRC :Freenode memiliki saluran yang sangat aktif yang disebut #postgres, di mana pengguna saling membantu memahami konsep, memperbaiki kesalahan, atau menemukan sumber daya lainnya. Daftar lengkap saluran freenode yang tersedia untuk semua hal PostgreSQL dapat ditemukan di situs web PostgreSQL.org.
  • Daftar Surat :PostgreSQL memiliki beberapa milis yang dapat digabungkan. Pertanyaan / masalah yang lebih panjang dapat dikirim ke sini, dan dapat menjangkau lebih banyak orang daripada IRC pada waktu tertentu. Daftar dapat ditemukan di Situs Web PostgreSQL, dan daftar pgsql-general atau pgsql-admin adalah sumber yang bagus.
  • Slack :Komunitas PostgreSQL juga berkembang pesat di Slack, dan dapat bergabung di postgresteam.slack.com. Sama seperti IRC, komunitas aktif tersedia untuk menjawab pertanyaan dan terlibat dalam semua hal PostgreSQL.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. BUAT TABEL PostgreSQL

  2. Kesalahan:pg_config executable tidak ditemukan saat menginstal psycopg2 di Alpine di Docker

  3. Rails + Postgres drop error:database sedang diakses oleh pengguna lain

  4. Gabung mandiri rekursif Postgresql

  5. PostgreSQL - Tambahkan kunci ke setiap objek dari array JSONB