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. JikaWHEREklausa 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_idtidak ada dalam dokumen asli Anda. -
Masih ada kasus sudut ambiguitas . Jika elemen ada dan disetel ke JSON
null, Anda juga mendapatkan SQLNULLsebagai 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
jsonsebagai tipe pengembalian, saya hanya menyimpannya. Tetapi jika fungsinya tidak diperbarui, Anda tidak dapat memastikan mengapa Anda mendapatkanfalse. Mungkin tidak ada baris denganidyang 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);