Již jste zjistili, že můžete otestovat výraz user_info->>'username'
pro NULL. Vaše funkce je však stále velmi neefektivní . A stále existují nejasnosti .
Lepší řešení v Postgres 9.3
Je nákladné aktualizovat řádek opakovaně pro více sloupců. Postgres zapisuje novou verzi řádku pro každou aktualizaci. Použijte jednu AKTUALIZACE
pokud je to možné:
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;
Volejte:
SELECT sp_update_user(123, '{"firstname": "jon", "lastname": "doe"}')
-
To je podstatně rychlejší pro více sloupců, protože pouze jeden
UPDATE
(nejvýše) se provede. PokudWHERE
klauzule se nevyhodnotí jakopravda
, neproběhne žádná aktualizace a dostanete'{"success":false}'
jako výsledek. -
Pokud jsou někdy hodnoty v tabulce již takové, na které se mění, je možná další optimalizace. Zvažte poslední odstavec této související odpovědi:
-
Proměnná / parametr
user_id
ve vašem originále chybí. -
Stále existuje nejednoznačnost rohového pouzdra . Pokud prvek existuje a je nastaven na JSON
null
, získáte také SQLNULL
jako výsledek. Zvažte:SELECT ('{"b": null}'::json->>'b') IS NULL AS b_is_null , ('{"c": 2}'::json->>'b') IS NULL AS b_missing;
-
Nejste si jisti, proč používáte datový typ
json
jako návratový typ jsem si to nechal. Pokud se však funkce neaktualizuje, nemůžete si být jisti, proč se zobrazujefalse
. Nemusí existovat žádný řádek s danýmid
, názvy klíčů'firstname'
a'příjmení'
může chybět – nebo býtnull
...
Vynikající řešení v Postgres 9.4
K dispozici je čisté a jednoduché řešení v Postgres 9.4 pomocí jsonb
pomocí
SELECT ('{"b": null}'::jsonb ? 'b') AS b_is_null
, ('{"c": 2}'::jsonb ? 'b') AS b_missing;
A ?|
a ?&
varianty
pro kontrolu více klíčů najednou.
Takže můžeme implementovat:
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;
Tato volání nyní fungují podle očekávání:
SELECT sp_update_user(123, '{"firstname": null, "lastname": "doe1"}'::jsonb);
SELECT sp_update_user(123, '{"firstname": "doris"}'::jsonb);