PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Проверете дали ключът съществува в JSON с PL/pgSQL?

Вече открихте, че можете да тествате израза user_info->>'username' за NULL. Но вашата функция все още е много неефективна . И все още има неяснотита .

По-добро решение в Postgres 9.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 (най-много) се изпълнява. Ако WHERE клаузата не дава оценка на true , изобщо не се извършва актуализация и получавате '{"success":false}' като резултат.

  • Ако понякога стойностите в таблицата вече са това, на което се променят, е възможна друга оптимизация. Помислете за последния абзац на този свързан отговор:

  • Променливата/параметър user_id липсва във вашия оригинал.

  • Все още има ъглов случайнеяснотата . Ако елементът съществува и е зададен на JSON null , вие също получавате SQL NULL като резултат. Помислете за следното:

    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 ...


Превъзходно решение в Postgres 9.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);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. оптимизирайте заявката в PostgreSQL

  2. PostgreSQL - създайте нова база данни чрез pgAdmin UI

  3. Грешно кодиране между Spring и PostgreSQL

  4. Как да премахнете условията от клаузата WHERE, ако параметрите са NULL

  5. Размито съпоставяне на низ в SQL