PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Kiểm tra xem khóa có tồn tại trong JSON với PL / pgSQL không?

Bạn đã thấy rằng bạn có thể kiểm tra biểu thức user_info->>'username' cho NULL. Nhưng chức năng của bạn vẫn rất kém hiệu quả . Và vẫn còn sự mơ hồ .

Giải pháp tốt hơn trong Postgres 9.3

Sẽ rất tốn kém khi cập nhật liên tục một hàng cho nhiều cột. Postgres viết một phiên bản hàng mới cho mỗi bản cập nhật. Sử dụng một đơn UPDATE nếu có thể:

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;

Gọi:

SELECT sp_update_user(123, '{"firstname": "jon", "lastname": "doe"}')
  • Điều này nhanh hơn đáng kể đối với nhiều cột, vì chỉ một UPDATE duy nhất (nhiều nhất) được thực thi. Nếu WHERE mệnh đề không đánh giá thành true , không có bản cập nhật nào xảy ra và bạn nhận được '{"success":false}' kết quả là.

  • Nếu đôi khi các giá trị trong bảng đã được thay đổi thành, thì có thể thực hiện một tối ưu hóa khác. Hãy xem xét đoạn cuối cùng của câu trả lời liên quan này:

  • Biến / tham số user_id bị thiếu trong bản gốc của bạn.

  • Vẫn còn một trường hợp góc không rõ ràng . Nếu phần tử tồn tại và được đặt thành JSON null , bạn cũng nhận được một SQL NULL kết quả là. Cân nhắc:

    SELECT ('{"b": null}'::json->>'b') IS NULL AS b_is_null
         , ('{"c": 2}'::json->>'b')    IS NULL AS b_missing;
    
  • Không chắc tại sao bạn sử dụng kiểu dữ liệu json là loại trả lại, tôi chỉ giữ điều đó. Nhưng nếu chức năng không cập nhật, bạn không thể chắc chắn tại sao bạn nhận được false . Có thể không có hàng với id đã cho , các tên khóa 'firstname''lastname' có thể bị thiếu - hoặc null ...


Giải pháp vượt trội trong Postgres 9.4

Có một sạch sẽ và giải pháp đơn giản trong Postgres 9.4 với jsonb với ? toán tử "sự tồn tại" - thậm chí có thể sử dụng một chỉ mục cho các bảng lớn hơn (không liên quan trong chức năng của bạn):

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

?|?& các biến thể để kiểm tra nhiều khóa cùng một lúc.
Vì vậy, chúng tôi có thể triển khai:

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;

Các cuộc gọi này hiện hoạt động như mong đợi:

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. Làm thế nào để phân biệt tên biến plpgsql trong mệnh đề BẬT MÂU THUẪN?

  2. Cách UNION hoạt động trong PostgreSQL

  3. Lỗi khi ánh xạ các mảng postgres trong Spring JPA

  4. PostgreSQL - Cột bí danh và CÓ

  5. Nhận xét ký tự / ký tự trong postgres / postgresql / psql?