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

Melewati nama kolom secara dinamis untuk variabel record di PostgreSQL

Bekerja dengan tabel dummy ini

CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)

Pertama, saya menyederhanakan dan membersihkan contoh Anda:

  • Menghapus beberapa kebisingan yang tidak relevan dengan pertanyaan.

  • RETURNS SETOF void hampir tidak masuk akal. Saya menggunakan RETURNS void sebagai gantinya.

  • Saya menggunakan text alih-alih character varying , hanya demi kesederhanaan.

  • Saat menggunakan SQL dinamis, Anda memiliki untuk melindungi dari injeksi SQL, saya menggunakan format() dengan %I pada kasus ini. Ada cara lain.

Masalah dasarnya adalah SQL sangat kaku dengan tipe dan pengidentifikasi. Anda beroperasi dengan tabel dinamis name serta dengan nama field dinamis dari sebuah record - sebuah anonim rekam dalam contoh asli Anda. Pl/pgSQL tidak dilengkapi dengan baik untuk menangani hal ini. Postgres tidak tahu apa yang di dalam catatan anonim. Hanya setelah Anda menetapkan catatan ke tipe terkenal dapatkah Anda mereferensikan masing-masing bidang.
Ini adalah pertanyaan yang terkait erat, mencoba mengatur bidang catatan dengan nama dinamis:
Cara menyetel nilai bidang variabel komposit menggunakan SQL dinamis

Fungsi dasar

CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
  RETURNS void AS
$func$ 
DECLARE
   srowdata record;
   reqfield text := 'my_num';   -- assigning at declaration time for convenience
   value    numeric;
BEGIN

RAISE NOTICE 'id: %', id; 

EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
USING  id
INTO   srowdata;

RAISE NOTICE 'srowdata: %', srowdata;

RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;

/* This does not work, even with dynamic SQL
EXECUTE format('SELECT ($1).%I', reqfield)
USING srowdata
INTO value;

RAISE NOTICE 'value: %', value;
*/

END
$func$ LANGUAGE plpgsql;

Telepon:

SELECT * from getrowdata1('foo', 1);

Bagian yang dikomentari akan memunculkan pengecualian:

tidak dapat mengidentifikasi kolom "my_num" dalam tipe data rekaman:SELECT * fromgetrowdata(1,'foo')

hstore

Anda perlu menginstal modul tambahan hstore untuk ini. Sekali per database dengan:

CREATE EXTENSION hstore;

Maka semua bisa bekerja seperti ini:

CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
  RETURNS void AS
$func$ 
DECLARE
   hstoredata hstore;
   reqfield   text := 'my_num';
   value      numeric;
BEGIN

RAISE NOTICE 'id: %', id; 

EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
USING  id
INTO   hstoredata;

RAISE NOTICE 'hstoredata: %', hstoredata;

RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';

value := hstoredata -> reqfield;

RAISE NOTICE 'value: %', value;

END
$func$ LANGUAGE plpgsql;

Telepon:

SELECT * from getrowdata2('foo', 1);

Tipe polimorfik

Alternatif tanpa menginstal modul tambahan.

Karena Anda memilih seluruh baris ke dalam variabel rekaman Anda, ada jenis yang ditentukan dengan baik untuk itu per definisi. Gunakan. Kata kuncinya adalah tipe polimorfik .

CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
  RETURNS void AS
$func$ 
DECLARE
   reqfield text := 'my_num';
   value    numeric;
BEGIN

RAISE NOTICE 'id: %', id; 

EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
USING  id
INTO   _tbl;

RAISE NOTICE '_tbl: %', _tbl;

RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;

EXECUTE 'SELECT ($1).' || reqfield   -- requfield must be SQLi-safe or escape
USING _tbl
INTO  value;

RAISE NOTICE 'value: %', value;

END
$func$ LANGUAGE plpgsql;

Telepon:

SELECT * from getrowdata3(NULL::foo, 1);

-> SQLfiddle

  • Saya (ab-) menggunakan parameter input _tbl untuk tiga tujuan di sini:

    • Menyediakan jenis yang terdefinisi dengan baik catatan
    • Menyediakan nama tabel, secara otomatis memenuhi syarat untuk skema
    • Berfungsi sebagai variabel.
  • Penjelasan lebih lanjut dalam jawaban terkait ini (bab terakhir):
    Refactor fungsi PL/pgSQL untuk mengembalikan output dari berbagai kueri SELECT




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara membulatkan ke X menit terdekat dengan PL/pgSQL?

  2. Cara Mendefinisikan Kunci Utama Peningkatan Otomatis di PostgreSQL

  3. PostgreSQL:antara dengan datetime

  4. Lihat dan hapus cache/buffer Postgres?

  5. isumeric() dengan PostgreSQL