式user_info->>'username'
をテストできることはすでにわかっています。 NULLの場合。しかし、あなたの機能はまだ非常に非効率的 。そして、まだあいまいさがあります 。
Postgres9.3のより良いソリューション
複数の列に対して行を繰り返し更新するのはコストがかかります。 Postgresは、更新ごとに新しい行バージョンを書き込みます。 シングルを使用する UPDATE
可能であれば:
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;
電話:
SELECT sp_update_user(123, '{"firstname": "jon", "lastname": "doe"}')
-
UPDATE
が1つしかないため、これは複数の列で大幅に高速になります。 (せいぜい)実行されます。WHERE
の場合 句はtrue
と評価されません 、更新はまったく行われず、'{"success":false}'
が表示されます。 結果として。 -
テーブル内の値がすでに変更されている場合は、別の最適化が可能です。この関連する回答の最後の段落を検討してください:
-
変数/パラメーター
user_id
オリジナルにありません。 -
まだコーナーケースがありますあいまいさ 。要素が存在し、 JSON
null
に設定されている場合 、SQLNULL
も取得します 結果として。検討してください:SELECT ('{"b": null}'::json->>'b') IS NULL AS b_is_null , ('{"c": 2}'::json->>'b') IS NULL AS b_missing;
-
データ型
json
を使用する理由がわからない リターンタイプとして、そのままにしておきました。ただし、関数が更新されない場合、false
が発生する理由がわかりません。 。指定されたid
の行がない可能性があります 、キー名'firstname'
および'lastname'
欠落している可能性があります-またはnull
...
Postgres9.4の優れたソリューション
クリーンがあります Postgres 9.4のシンプルなソリューション jsonb
を使用 ?
「存在」演算子
-これは、より大きなテーブルのインデックスを使用することもできます(関数には関係ありません):
SELECT ('{"b": null}'::jsonb ? 'b') AS b_is_null
, ('{"c": 2}'::jsonb ? 'b') AS b_missing;
そして、 ?|
および?&
バリアント
一度に複数のキーをチェックします。
実装できるように:
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;
これらの呼び出しは現在期待どおりに機能します:
SELECT sp_update_user(123, '{"firstname": null, "lastname": "doe1"}'::jsonb);
SELECT sp_update_user(123, '{"firstname": "doris"}'::jsonb);