sql >> Databáze >  >> RDS >> PostgreSQL

Zkontrolujte, zda existuje klíč v JSON s PL/pgSQL?

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. Pokud WHERE klauzule se nevyhodnotí jako pravda , 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é SQL NULL 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 zobrazuje false . Nemusí existovat žádný řádek s daným id , názvy klíčů 'firstname' a 'příjmení' může chybět – nebo být null ...


Vynikající řešení v Postgres 9.4

K dispozici je čisté a jednoduché řešení v Postgres 9.4 pomocí jsonb pomocí ? operátor "existence" - který může dokonce používat index pro větší tabulky (není relevantní ve vaší funkci):

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);


  1. Počítání počtu shodných slov

  2. Nelze se připojit k Oracle pomocí tns

  3. Cursor For Loop s dynamickým SQL příkazem

  4. Jak mohu vypočítat agregované ovlivněné řádky, pokud je v mém bloku PLSQL více dotazů DML?