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

Fungsi Postgres mengembalikan baris sebagai nilai JSON

Saya melihat dua masalah utama:
1. Anda tidak dapat memasukkan UPDATE menjadi subquery sama sekali . Anda dapat menyelesaikannya dengan pengubah data CTE seperti Patrick mendemonstrasikan , tetapi itu lebih mahal dan bertele-tele daripada yang diperlukan untuk kasus yang dihadapi.
2. Anda memiliki konflik penamaan yang berpotensi berbahaya , yang belum ditangani.

Kueri/fungsi yang lebih baik

Meninggalkan pembungkus fungsi SQL untuk saat ini (kita akan kembali ke sana). Anda dapat menggunakan UPDATE sederhana dengan RETURNING klausa:

UPDATE tbl
SET    value1 = 'something_new'
WHERE  id = 123
RETURNING row_to_json(ROW(value1, value2));

RETURNING klausa memungkinkan ekspresi sewenang-wenang yang melibatkan kolom dari baris yang diperbarui. Itu lebih pendek dan lebih murah daripada CTE pengubah data.

Masalah yang tersisa:konstruktor baris ROW(...) tidak mempertahankan nama kolom (yang merupakan kelemahan yang diketahui), jadi Anda mendapatkan kunci umum dalam nilai JSON Anda:

row_to_json
{"f1":"something_new","f2":"what ever is in value2"}

Di Postgres 9.3 Anda memerlukan CTE fungsi lain untuk merangkum langkah pertama atau gips ke tipe baris yang terdefinisi dengan baik. Detail:

Di Postgres 9.4 cukup gunakan json_build_object() atau json_object() :

UPDATE tbl
SET    value1 = 'something_new'
WHERE  id = 123
RETURNING json_build_object('value1', value1, 'value2', value2);

Atau:

...
RETURNING json_object('{value1, value2}', ARRAY[value1, value2]);

Sekarang Anda mendapatkan nama kolom asli atau apa pun yang Anda pilih sebagai nama kunci:

row_to_json
{"value1":"something_new","value2":"what ever is in value2"}

Sangat mudah untuk membungkus ini dalam sebuah fungsi, yang membawa kita ke masalah kedua Anda ...

Konflik penamaan

Dalam fungsi asli Anda, Anda menggunakan nama yang identik untuk parameter fungsi dan nama kolom. Ini biasanya merupakan ide yang sangat buruk . Anda perlu memahami secara mendalam pengidentifikasi mana yang muncul lebih dulu dalam cakupan mana.

Dalam kasus yang ada, hasilnya benar-benar tidak masuk akal:

Create Or Replace Function ExampleTable_Update (id bigint, value1 text) Returns 
...
    Update ExampleTable
    Set Value1 = value1
    Where id = id
    Returning Value1, Value2;
...
$$ Language SQL;

Meskipun Anda tampaknya mengharapkan contoh kedua dari id akan mereferensikan parameter fungsi, tidak. Nama kolom didahulukan dalam lingkup pernyataan SQL, instance kedua merujuk ke kolom. menghasilkan ekspresi yang selalu true kecuali untuk nilai NULL di id . Akibatnya, Anda akan memperbarui semua baris , yang dapat menyebabkan kehilangan data yang sangat besar .Yang lebih parah, Anda mungkin tidak menyadarinya sampai nanti, karena fungsi SQL akan mengembalikan satu baris arbitrer seperti yang didefinisikan oleh RETURNING klausa fungsi (mengembalikan satu baris, bukan kumpulan baris).

Dalam kasus khusus ini, Anda akan mendapatkan "keberuntungan", karena Anda juga memiliki value1 = value1 , yang menimpa kolom dengan nilai yang sudah ada sebelumnya, secara efektif melakukan .. tidak ada dengan cara yang sangat mahal (kecuali pemicu melakukan sesuatu). Anda mungkin bingung untuk mendapatkan baris arbitrer dengan value1 unchanged yang tidak berubah sebagai hasilnya.

Jadi, jangan.

Hindari potensi konflik penamaan seperti ini kecuali Anda tahu persis apa yang Anda lakukan (yang jelas tidak demikian). Satu konvensi yang saya suka adalah menambahkan garis bawah untuk parameter dan nama variabel dalam fungsi, sementara nama kolom tidak pernah dimulai dengan garis bawah. Dalam banyak kasus, Anda dapat menggunakan referensi posisi agar tidak ambigu:$1 , $2 , ..., tetapi itu hanya mengabaikan setengah dari masalah. Metode apa pun bagus selama Anda menghindari konflik penamaan . Saya sarankan:

CREATE OR REPLACE FUNCTION foo (_id bigint, _value1 text)
   RETURNS json AS
$func$
UPDATE tbl
SET    value1 = _value1
WHERE  id     = _id
RETURNING json_build_object('value1', value1, 'value2', value2);
$func$  LANGUAGE sql;

Perhatikan juga bahwa ini mengembalikan nilai kolom yang sebenarnya di value1 setelah UPDATE , yang mungkin atau mungkin tidak sama dengan parameter input Anda _value1 . Mungkin ada aturan database atau pemicu yang mengganggu ...



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Koneksi ditolak (PGError) (postgresql dan Rails)

  2. Bagaimana saya bisa menetapkan batas ukuran untuk tipe data int di PostgreSQL 9.5

  3. Cara mengisi database postgresql dengan Mrjob dan Hadoop

  4. Menjalankan program Java dari baris perintah Linux yang membutuhkan file tambahan

  5. Pencarian teks lengkap pada substring di PostgreSQL