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

Kembalikan tabel dinamis dengan kolom yang tidak diketahui dari fungsi PL/pgSQL

Ini sulit untuk dipecahkan, karena SQL menuntut untuk mengetahui tipe pengembalian pada waktu panggilan .
Selain itu, fungsi plpgsql harus memiliki tipe pengembalian yang didefinisikan dengan baik .

Jika Anda memilih untuk mengembalikan catatan anonim , Anda mendapatkan apa yang Anda tetapkan:catatan anonim. Postgres tidak tahu apa yang ada di dalamnya. Oleh karena itu, daftar definisi kolom diperlukan untuk menguraikan jenisnya.

Ada berbagai solusi, tergantung pada persyaratan yang tepat. Jika Anda memiliki cara untuk mengetahui jenis pengembalian pada waktu panggilan , saya menyarankan tipe polimorfik sebagaimana diuraikan dalam bab terakhir dari jawaban ini ("Berbagai jenis tabel lengkap"):
Memperbaiki fungsi PL/pgSQL untuk mengembalikan output dari berbagai kueri SELECT

Tapi itu tidak mencakup penambahan kolom lain ke tipe kembalian saat runtime di dalam fungsi . Itu tidak mungkin. Saya akan memikirkan kembali seluruh pendekatan .

Adapun pendekatan Anda saat ini, hal terdekat yang dapat saya pikirkan adalah tabel sementara (atau kursor), yang Anda kueri dalam panggilan kedua dalam satu transaksi .

Anda memiliki beberapa masalah lain dalam kode Anda . Lihat catatan di bawah.

Bukti konsep

CREATE OR REPLACE FUNCTION f_tbl_plus_infowindow (_tbl regclass) -- regclass!
  RETURNS void AS  -- no direct return type
$func$
DECLARE
   -- appending _tmp for temp table
   _tmp text := quote_ident(_tbl::text || '_tmp');
BEGIN

-- Create temp table only for duration of transaction
EXECUTE format(
   'CREATE TEMP TABLE %s ON COMMIT DROP AS TABLE %s LIMIT 0', _tmp, _tbl);

IF EXISTS (
   SELECT 1
   FROM   pg_attribute a
   WHERE  a.attrelid = _tbl
   AND    a.attname  = 'infowindow'
   AND    a.attisdropped = FALSE)
THEN
   EXECUTE format('INSERT INTO %s SELECT * FROM %s', _tmp, _tbl);
ELSE
  -- This is assuming a NOT NULL column named "id"!
   EXECUTE format($x$
      ALTER  TABLE %1$s ADD COLUMN infowindow text;
      INSERT INTO %1$s
      SELECT *, 'ID: ' || id::text
      FROM   %2$s $x$
     ,_tmp, _tbl);
END IF;

END
$func$ LANGUAGE plpgsql;

Panggilan harus dalam satu transaksi. Anda mungkin harus memulai transaksi eksplisit, tergantung pada klien Anda.

BEGIN;
SELECT f_tbl_plus_infowindow ('tbl');
SELECT * FROM tbl_tmp;  -- do something with the returned rows
ROLLBACK;               -- or COMMIT, does not matter here

SQL Fiddle.

Atau Anda bisa membiarkan tabel sementara hidup selama sesi. Namun, berhati-hatilah dengan penamaan yang bertabrakan dengan panggilan berulang.

Catatan

  • Gunakan nama parameter alih-alih ALIAS yang sudah usang perintah.

  • Untuk benar-benar "default" ke skema saat ini, gunakan kueri sederhana yang saya tampilkan. Menggunakan regclass melakukan trik secara otomatis. Detail:

    • Nama tabel sebagai parameter fungsi PostgreSQL

    Selain itu, ini juga menghindari kesalahan sintaks dan kemungkinan injeksi SQL dari nama tabel non-standar (atau dengan format yang salah) dalam kode asli Anda.

  • Kode di ELSE . Anda klausa tidak akan berfungsi sama sekali.

  • TABLE tbl; pada dasarnya adalah kependekan dari SELECT * FROM tbl; .

  • Detail tentang format() dalam manual.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara cepat untuk menemukan jumlah baris tabel di PostgreSQL

  2. Izinkan null di kolom unik

  3. `pg_tblspc` hilang setelah penginstalan versi terbaru OS X (Yosemite atau El Capitan)

  4. Bagaimana Atand() Bekerja di PostgreSQL

  5. Batasan yang ditentukan DEFERRABLE AWAL SEGERA masih DEFERRED?