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

Các giá trị json trong MySQL SUM được nhóm bằng các khóa json

TL; DR: có, nó có thể được thực hiện mà không cần biết trước các tên khóa và không có định dạng dữ liệu thay thế nào có bất kỳ lợi thế nào so với định dạng ban đầu.

Điều này có thể được thực hiện mà không cần biết trước các tên khóa nhưng thật khó ... về cơ bản bạn phải xem xét mọi giá trị trong bảng để xác định tập hợp các khóa riêng biệt trong bảng trước khi bạn có thể tính tổng chúng. Do yêu cầu này và thực tế là các định dạng dữ liệu thay thế đều có thể có nhiều khóa cho mỗi mục nhập, nên không có lợi thế khi sử dụng bất kỳ định dạng nào trong số chúng.

Vì bạn phải tìm tất cả các khóa riêng biệt, nên việc tính tổng trở nên dễ dàng khi bạn đang tìm kiếm chúng. Hàm và thủ tục này kết hợp với nhau sẽ thực hiện điều đó. Hàm, json_merge_sum , nhận hai giá trị JSON và hợp nhất chúng, tổng các giá trị mà khóa xuất hiện trong cả hai giá trị, ví dụ:

SELECT json_sum_merge('{"key1": 1, "key2": 3}', '{"key3": 1, "key2": 2}')

Đầu ra:

{"key1": 1, "key2": 5, "key3": 1}

Mã chức năng:

DELIMITER //
DROP FUNCTION IF EXISTS json_merge_sum //
CREATE FUNCTION json_sum_merge(IN j1 JSON, IN total JSON) RETURNS JSON
BEGIN
  DECLARE knum INT DEFAULT 0;
  DECLARE jkeys JSON DEFAULT JSON_KEYS(j1);
  DECLARE kpath VARCHAR(20);
  DECLARE v INT;
  DECLARE l INT DEFAULT JSON_LENGTH(jkeys);
  kloop: LOOP
    IF knum >= l THEN
      LEAVE kloop;
    END IF;
    SET kpath = CONCAT('$.', JSON_EXTRACT(jkeys, CONCAT('$[', knum, ']')));
    SET v = JSON_EXTRACT(j1, kpath);
    IF JSON_CONTAINS_PATH(total, 'one', kpath) THEN
      SET total = JSON_REPLACE(total, kpath, JSON_EXTRACT(total, kpath) + v);
    ELSE
      SET total = JSON_SET(total, kpath, v);
    END IF;
    SET knum = knum + 1;
  END LOOP kloop;
  RETURN total;
END

Thủ tục, count_keys , thực hiện tương đương với GROUP BY mệnh đề. Nó tìm thấy tất cả các giá trị riêng biệt của col1 trong bảng và sau đó gọi json_sum_merge cho mỗi hàng có giá trị đó là col1 . Lưu ý rằng truy vấn chọn hàng thực hiện SELECT ... INTO một biến giả để không có đầu ra nào được tạo và sử dụng MIN() để đảm bảo chỉ có một kết quả (để nó có thể được gán cho một biến).

Thủ tục:

DELIMITER //
DROP PROCEDURE IF EXISTS count_keys //
CREATE PROCEDURE count_keys()
BEGIN
  DECLARE finished INT DEFAULT 0;
  DECLARE col1val VARCHAR(20);
  DECLARE col1_cursor CURSOR FOR SELECT DISTINCT col1 FROM table2;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished=1;
  OPEN col1_cursor;
  col1_loop: LOOP
    FETCH col1_cursor INTO col1val;
    IF finished=1 THEN
      LEAVE col1_loop;
    END IF;
    SET @total = '{}';
    SET @query = CONCAT("SELECT MIN(@total:=json_sum_merge(col2, @total)) INTO @json FROM table2 WHERE col1='", col1val, "'");
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    SELECT col1val AS col1, @total AS col2;
  END LOOP col1_loop;
END

Đối với một ví dụ lớn hơn một chút:

col1    col2    
aaa     {"key1": 1, "key2": 3}
bbb     {"key1": 4, "key2": 2}
aaa     {"key1": 50, "key3": 0}
ccc     {"key2": 5, "key3": 1, "key4": 3}
bbb     {"key1": 5, "key2": 1, "key5": 3}

CALL count_keys() sản xuất:

col1    col2    
aaa     {"key1": 51, "key2": 3, "key3": 0}
bbb     {"key1": 9, "key2": 3, "key5": 3}
ccc     {"key2": 5, "key3": 1, "key4": 3}

Lưu ý rằng tôi đã gọi bảng là table2 trong thủ tục, bạn sẽ cần phải chỉnh sửa điều đó (trong cả hai truy vấn) cho phù hợp.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tạo bảng bằng vb.net, mysql

  2. Hiệu suất chế độ xem MySQL

  3. Biến mảng trong mysql

  4. MySQL chọn các hàng trên cùng với các giá trị điều kiện giống nhau

  5. MySqlCommand Command.Parameters.Add đã lỗi thời