sql >> データベース >  >> RDS >> Mysql

jsonキーでグループ化されたMySQLSUMjson値

    TL; DR: はい、事前にキー名を知らなくても実行できます。また、代替データ形式のいずれも元の形式に勝る利点はありません。

    これは、キー名を事前に知らなくても実行できますが、面倒です...基本的に、テーブル内のすべての値を調べて、合計する前にテーブル内の個別のキーのセットを判別する必要があります。この要件と、代替データ形式はすべてエントリごとに複数のキーを持つことができるという事実のために、それらのいずれかを使用する利点はありません。

    すべての個別のキーを探す必要があるため、それらを探しているときに合計を行うのは簡単です。この関数とプロシージャは一緒にそれを行います。関数json_merge_sum 、2つのJSON値を取得してそれらをマージし、両方の値にキーが表示される値を合計します。例:

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

    出力:

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

    機能コード:

    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
    

    プロシージャ、count_keysGROUP BYと同等の機能を実行します 句。 col1のすべての個別の値を検索します テーブル内でjson_sum_mergeを呼び出します col1の値を持つ行ごとに 。行選択クエリはSELECT ... INTOを実行することに注意してください 出力が生成されないようにするダミー変数であり、MIN()を使用します 結果が1つだけであることを確認します(変数に割り当てることができるようにします)。

    手順:

    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
    

    少し大きい例:

    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() 生成:

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

    テーブルをtable2と呼んでいることに注意してください 手順では、それに合わせて(両方のクエリで)編集する必要があります。



    1. C#でSMOを使用してSQL Serverの利用可能なインスタンスを一覧表示するにはどうすればよいですか?

    2. UTF8文字列のMD5ハッシュを計算します

    3. フィールド「id」にはデフォルト値がありませんか?

    4. INSERT INTO...RETURNING-あいまいな列参照