sql >> Database teknologi >  >> RDS >> PostgreSQL

Tjek, om nøglen findes i en JSON med PL/pgSQL?

Du har allerede fundet ud af, at du kan teste udtrykket user_info->>'brugernavn' for NULL. Men din funktion er stadig meget ineffektiv . Og der er stadig uklarheder .

Bedre løsning i Postgres 9.3

Det er dyrt at opdatere en række gentagne gange for flere kolonner. Postgres skriver en ny rækkeversion for hver opdatering. Brug en enkelt OPDATERING hvis det overhovedet er muligt:

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;

Ring til:

SELECT sp_update_user(123, '{"firstname": "jon", "lastname": "doe"}')
  • Dette er væsentligt hurtigere for flere kolonner, da kun en enkelt OPDATERING (højst) udføres. Hvis WHERE klausul evalueres ikke til true , der sker ingen opdatering overhovedet, og du får '{"success":false}' som resultat.

  • Hvis værdierne i tabellen nogle gange allerede er, hvad de ændres til, er en anden optimering mulig. Overvej det sidste afsnit af dette relaterede svar:

  • Variablen / parameteren user_id mangler i din original.

  • Der er stadig en tvetydighed i hjørnet . Hvis elementet findes og er sat til JSON null , får du også en SQL NULL som resultat. Overvej:

    SELECT ('{"b": null}'::json->>'b') IS NULL AS b_is_null
         , ('{"c": 2}'::json->>'b')    IS NULL AS b_missing;
    
  • Ikke sikker på, hvorfor du bruger datatypen json som returtype beholdt jeg det bare. Men hvis funktionen ikke opdateres, kan du ikke være sikker på, hvorfor du får false . Der er muligvis ingen række med det angivne id , nøglenavnene 'fornavn' og 'efternavn' kunne mangle - eller være null ...


Super løsning i Postgres 9.4

Der er en ren og enkel løsning i Postgres 9.4 med jsonb med <-koden>? "eksistens" operatør - som endda kan bruge et indeks til større tabeller (ikke relevant i din funktion):

SELECT ('{"b": null}'::jsonb ? 'b') AS b_is_null
     , ('{"c": 2}'::jsonb ? 'b')    AS b_missing;

Og ?| og ?& varianter at tjekke for flere nøgler på én gang.
Så vi kan implementere:

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;

Disse opkald fungerer som forventet nu:

SELECT sp_update_user(123, '{"firstname": null, "lastname": "doe1"}'::jsonb);
SELECT sp_update_user(123, '{"firstname": "doris"}'::jsonb);


  1. Brug af tuples i SQL IN-klausul

  2. slet sqlite-database ved opdatering af ny version af applikationen

  3. Hvordan profilerer man PostgreSQL-databasen?

  4. Selvlukkende tags i XML i SQL Server