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. JikaWHERE
klausa tidak mengevaluasi ketrue
, 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 SQLNULL
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 mendapatkanfalse
. Mungkin tidak ada baris denganid
yang diberikan , nama kunci'firstname'
dan'lastname'
bisa hilang - atau menjadinull
...
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);