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

Periksa apakah ada kunci di JSON dengan PL/pgSQL?

Anda telah menemukan bahwa Anda dapat menguji ekspresi user_info->>'username' untuk NULL. Tetapi fungsi Anda masih sangat tidak efisien . Dan masih ada ambiguitas .

Solusi yang lebih baik di Postgres 9.3

Mahal untuk memperbarui baris berulang kali untuk beberapa kolom. Postgres menulis versi baris baru untuk setiap pembaruan. Gunakan tunggal UPDATE jika memungkinkan:

CREATE OR REPLACE FUNCTION sp_update_user(_user_id int, _user_info json)
  RETURNS json AS
$func$
BEGIN
   UPDATE users u
   SET    firstname = COALESCE(_user_info->>'firstname', u.firstname)
        , lastname  = COALESCE(_user_info->>'lastname' , u.lastname)
   WHERE  id = sp_update_user._user_id
   AND   ((_user_info->>'firstname') IS NOT NULL OR
          (_user_info->>'lastname')  IS NOT NULL);

   IF FOUND THEN
      RETURN '{"success":true}'::json;
   ELSE
      RETURN '{"success":false}'::json;
   END IF;
END
$func$  LANGUAGE plpgsql;

Telepon:

SELECT sp_update_user(123, '{"firstname": "jon", "lastname": "doe"}')
  • Ini jauh lebih cepat untuk beberapa kolom, karena hanya satu UPDATE (paling banyak) dieksekusi. Jika WHERE klausa tidak mengevaluasi ke true , tidak ada pembaruan sama sekali dan Anda mendapatkan '{"success":false}' sebagai hasilnya.

  • Jika terkadang nilai dalam tabel sudah berubah menjadi apa, pengoptimalan lain mungkin dilakukan. Pertimbangkan paragraf terakhir dari jawaban terkait ini:

  • Variabel / parameter user_id tidak ada dalam dokumen asli Anda.

  • Masih ada kasus sudut ambiguitas . Jika elemen ada dan disetel ke JSON null , Anda juga mendapatkan SQL NULL sebagai hasil. Pertimbangkan:

    SELECT ('{"b": null}'::json->>'b') IS NULL AS b_is_null
         , ('{"c": 2}'::json->>'b')    IS NULL AS b_missing;
    
  • Tidak yakin mengapa Anda menggunakan tipe data json sebagai tipe pengembalian, saya hanya menyimpannya. Tetapi jika fungsinya tidak diperbarui, Anda tidak dapat memastikan mengapa Anda mendapatkan false . Mungkin tidak ada baris dengan id yang diberikan , nama kunci 'firstname' dan 'lastname' bisa hilang - atau menjadi null ...


Solusi unggul di Postgres 9.4

Ada bersih dan solusi sederhana di Postgres 9.4 dengan jsonb dengan ? operator "keberadaan" - yang bahkan dapat menggunakan indeks untuk tabel yang lebih besar (tidak relevan dengan fungsi Anda):

SELECT ('{"b": null}'::jsonb ? 'b') AS b_is_null
     , ('{"c": 2}'::jsonb ? 'b')    AS b_missing;

Dan ?| dan ?& varian untuk memeriksa beberapa kunci sekaligus.
Agar kita dapat menerapkan:

CREATE OR REPLACE FUNCTION sp_update_user(_user_id int, _user_info jsonb)
  RETURNS jsonb AS
$func$
BEGIN
   UPDATE users u
   SET    firstname = CASE WHEN _user_info ? 'firstname' THEN _user_info->>'firstname' ELSE u.firstname END
        , lastname  = CASE WHEN _user_info ? 'lastname'  THEN _user_info->>'lastname'  ELSE u.lastname  END
   WHERE  id = sp_update_user._user_id
   AND    _user_info ?| '{firstname,lastname}';

   IF FOUND THEN
      RETURN '{"success":true}'::jsonb;
   ELSE
      RETURN '{"success":false}'::jsonb;
   END IF;
END
$func$  LANGUAGE plpgsql;

Panggilan ini berfungsi seperti yang diharapkan sekarang:

SELECT sp_update_user(123, '{"firstname": null, "lastname": "doe1"}'::jsonb);
SELECT sp_update_user(123, '{"firstname": "doris"}'::jsonb);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL menemukan kombinasi umum pasangan pada kolom yang sama

  2. Tambahkan Minggu ke Tanggal di PostgreSQL

  3. menggunakan logika kondisional :periksa apakah ada catatan; jika ya, perbarui, jika tidak, buatlah

  4. Rails .where() kueri tidak berfungsi

  5. Simpan kueri umum sebagai kolom?