実現したいこと
以下のようなテーブルがあります。
SQL
1DROP TABLE IF EXISTS `logs`; 2CREATE TABLE `logs` ( 3 `task_id` int(11) NOT NULL, 4 `mac` varchar(17) NOT NULL, 5 `collection_time` timestamp NOT NULL DEFAULT current_timestamp(), 6 `mv` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`mv`)), 7 `response` int(11) NOT NULL DEFAULT 0, 8 PRIMARY KEY (`task_id`,`mac`,`collection_time`) 9) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 10
SQL
1INSERT INTO `logs` VALUES 2(1,'a','2025-02-20 00:00:00','{"20":1}',1), 3(1,'b','2025-02-20 00:00:00','{"20":2, "25":3}', 1), 4(1,'c','2025-02-20 00:00:00','{"20":4, "25":5, "30":6}', 1), 5(1,'d','2025-02-20 00:00:00','{"20":7, "25":8, "30":9, "35":10}', 1), 6(1,'a','2025-02-20 00:01:00','{"20":11}',1), 7(1,'b','2025-02-20 00:01:00','{"20":12, "25":13}', 1), 8(1,'c','2025-02-20 00:01:00','{"20":14, "25":15, "30":16}', 1), 9(1,'d','2025-02-20 00:01:00','{"20":17, "25":18, "30":19, "35":20}', 1); 10
SQL
1SELECT collection_time, mac, mv FROM logs ORDER BY collection_time, mac;
+---------------------+-----+------------------------------------------+
| collection_time | mac | mv |
+---------------------+-----+------------------------------------------+
| 2025-02-20 00:00:00 | a | {"20":1} |
| 2025-02-20 00:00:00 | b | {"20":2, "25":3} |
| 2025-02-20 00:00:00 | c | {"20":4, "25":5, "30":6} |
| 2025-02-20 00:00:00 | d | {"20":7, "25":8, "30":9, "35":10} |
| 2025-02-20 00:01:00 | a | {"20":11} |
| 2025-02-20 00:01:00 | b | {"20":12, "25":13} |
| 2025-02-20 00:01:00 | c | {"20":14, "25":15, "30":16} |
| 2025-02-20 00:01:00 | d | {"20":17, "25":18, "30":19, "35":20} |
+---------------------+-----+------------------------------------------+
このテーブルに対してクエリーを行い、以下のような結果を得たいと思います。
SQL
1SELECT 2 collection_time, 3 LEAST( 4 MIN(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."20"') = 0 THEN 99999 5 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."20"')) AS DECIMAL(10, 2)) END) 6, MIN(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."25"') = 0 THEN 99999 7 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."25"')) AS DECIMAL(10, 2)) END) 8, MIN(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."30"') = 0 THEN 99999 9 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."30"')) AS DECIMAL(10, 2)) END) 10, MIN(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."35"') = 0 THEN 99999 11 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."35"')) AS DECIMAL(10, 2)) END) 12 ) as min, 13 GREATEST( 14 MAX(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."20"') = 0 THEN -99999 15 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."20"')) AS DECIMAL(10, 2)) END) 16, MAX(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."25"') = 0 THEN -99999 17 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."25"')) AS DECIMAL(10, 2)) END) 18, MAX(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."30"') = 0 THEN -99999 19 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."30"')) AS DECIMAL(10, 2)) END) 20, MAX(CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$."35"') = 0 THEN -99999 21 ELSE CAST(JSON_UNQUOTE(JSON_EXTRACT(mv, '$."35"')) AS DECIMAL(10, 2)) END) 22 ) AS max, 23 '???' AS avg 24FROM logs 25GROUP BY collection_time;
+---------------------+-------+-------+-----+
| collection_time | min | max | avg |
+---------------------+-------+-------+-----+
| 2025-02-20 00:00:00 | 1.00 | 10.00 | ??? |
| 2025-02-20 00:01:00 | 11.00 | 20.00 | ??? |
+---------------------+-------+-------+-----+
この、avg の取得方法についてご教示ください。
avg の計算方法は以下の通りです。
SQL
1SELECT 2 collection_time, mac, 3 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.20') = 1 4 THEN JSON_EXTRACT(mv, '$.20') ELSE '' END + 5 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.25') = 1 6 THEN JSON_EXTRACT(mv, '$.25') ELSE '' END + 7 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.30') = 1 8 THEN JSON_EXTRACT(mv, '$.30') ELSE '' END + 9 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.35') = 1 10 THEN JSON_EXTRACT(mv, '$.35') ELSE '' END AS sum, 11 (JSON_CONTAINS_PATH(mv, 'one', '$.20')) + 12 (JSON_CONTAINS_PATH(mv, 'one', '$.25')) + 13 (JSON_CONTAINS_PATH(mv, 'one', '$.30')) + 14 (JSON_CONTAINS_PATH(mv, 'one', '$.35')) AS count, 15 ( 16 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.20') = 1 17 THEN JSON_EXTRACT(mv, '$.20') ELSE '' END + 18 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.25') = 1 19 THEN JSON_EXTRACT(mv, '$.25') ELSE '' END + 20 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.30') = 1 21 THEN JSON_EXTRACT(mv, '$.30') ELSE '' END + 22 CASE WHEN JSON_CONTAINS_PATH(mv, 'one', '$.35') = 1 23 THEN JSON_EXTRACT(mv, '$.35') ELSE '' END 24 ) / ( 25 (JSON_CONTAINS_PATH(mv, 'one', '$.20')) + 26 (JSON_CONTAINS_PATH(mv, 'one', '$.25')) + 27 (JSON_CONTAINS_PATH(mv, 'one', '$.30')) + 28 (JSON_CONTAINS_PATH(mv, 'one', '$.35')) 29 ) AS avg 30FROM logs 31ORDER BY collection_time, mac 32;
+---------------------+-----+------+-------+------+
| collection_time | mac | sum | count | avg |
+---------------------+-----+------+-------+------+
| 2025-02-20 00:00:00 | a | 1 | 1 | 1 |
| 2025-02-20 00:00:00 | b | 5 | 2 | 2.5 |
| 2025-02-20 00:00:00 | c | 15 | 3 | 5 |
| 2025-02-20 00:00:00 | d | 34 | 4 | 8.5 |
| 2025-02-20 00:01:00 | a | 11 | 1 | 11 |
| 2025-02-20 00:01:00 | b | 25 | 2 | 12.5 |
| 2025-02-20 00:01:00 | c | 45 | 3 | 15 |
| 2025-02-20 00:01:00 | d | 74 | 4 | 18.5 |
+---------------------+-----+------+-------+------+
1つの collection_time に対して、avg が mac の個数分作られています。
で、最終的に求めたい avg は、 (1 + 2.5 + 5 + 8.5 ) / 4 = 4.25 と (11 + 12.5 + 15 + 17.5) / 4 = 14 となります。
以上、よろしくお願いします。
発生している問題・分からないこと
平均の平均を求める方法を知りたい。
該当のソースコード
特になし
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
同様の質問を見つけることができなかった。
補足
テーブルはかなり省略して書いてありますが、実際にはJSONフィールドにキーが200以上あります。
レコード数が非常に多いため(JSONにしても、論理的には1億行オーバー)、このような構成になっています。データベースはMariaDB-10.11.9です。
回答1件
あなたの回答
tips
プレビュー