【问题标题】:MySQL aggregated sum of JSON objectsMySQL JSON 对象的聚合总和
【发布时间】:2023-03-10 16:39:01
【问题描述】:

我创建了新表并将详细信息作为 JSON 数据类型。我试图得到所有记录的总和。我可以获取每个值,但我不知道如何使用 group by 选项获取总和。

CREATE TABLE `Sample` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `details` json DEFAULT NULL,
  PRIMARY KEY (`id`)
)  CHARSET=latin1;

样本数据

 1. [{"id": 1, "name": "T1", "amount": "34.34", "percentage": "45"}, {"id": 3, "name": "T3", "amount": "30.34", "percentage": "45"}, {"id": 2, "name": "T2", "amount": "14.34", "percentage": "15"}]

 2. [{"id": 1, "name": "T1", "amount": "34.34", "percentage": "45"}, {"id": 2, "name": "T2", "amount": "30.34", "percentage": "45"}, {"id": 4, "name": "T4", "amount": "14.34", "percentage": "15"}]

我想要这 2 条记录的聚合组

输出数据

   [{"id": 1, "name": "T1", "amount": "68.68", "percentage": "45"}, {"id": 3, "name"`enter code here`: "T3", "amount": "30.34", "percentage": "45"}, {"id": 2, "name": "T2", "amount": "44.68", "percentage": "60"}, {"id": 4, "name": "T4", "amount": "14.34", "percentage": "15"}]

我尝试使用 JSON_EXTRACT(details, "$[*]") 但没有成功

【问题讨论】:

  • OFF-TOPIC:有原因吗,你为什么使用 json 数据类型?
  • 我将其保留为文本类型,但我不知道如何根据 JSON 键进行聚合

标签: mysql sql json


【解决方案1】:

更新:好的

首先,我肯定会建议对数据进行一点标准化。 您是否尝试过仅将对象存储到详细信息列中? 如果您需要存储具有每个样本 id 的数据组,您可以使用相关表。即:)

示例

id int 自动递增

mysql> create table Sample (id int(11) not null auto_increment, primary key(id));

详情

sample_id 整数 记录json

mysql> create table Details (sample_id int(11), record json);

填充您的数据

insert into Sample (id) values (1);
insert into Sample (id) values (2);

insert into Details (sample_id, record) values 
  (1, '{"id": 1, "name": "T1", "amount": "34.34", "percentage": "45"}'), 
  (1, '{"id": 3, "name": "T3", "amount": "30.34", "percentage": "45"}'), 
  (1, '{"id": 2, "name": "T2", "amount": "14.34", "percentage": "15"}');

insert into Details (sample_id, record) values 
  (2, '{"id": 1, "name": "T1", "amount": "34.34", "percentage": "45"}'),
  (2, '{"id": 2, "name": "T2", "amount": "30.34", "percentage": "45"}'),
  (2, '{"id": 4, "name": "T4", "amount": "14.34", "percentage": "15"}');

然后你可以做类似的事情

SELECT (
  JSON_OBJECT('id', id, 'amount', amount, 'percentage', percentage)
) FROM (
  SELECT 
    JSON_EXTRACT(record, "$.id") as id, 
    SUM(JSON_EXTRACT(record, "$.amount")) as amount, 
    AVG(JSON_EXTRACT(record, "$.percentage")) as percentage
  FROM Details 
  GROUP BY JSON_EXTRACT(record, "$.id")
) as t 

结果

+---------------------------------------------------------------------+
| (JSON_OBJECT('id', id, 'amount', amount, 'percentage', percentage)) |
+---------------------------------------------------------------------+
| {"id": 1, "amount": 68.68, "percentage": 45}                        |
| {"id": 2, "amount": 44.68, "percentage": 30}                        |
| {"id": 3, "amount": 30.34, "percentage": 45}                        |
| {"id": 4, "amount": 14.34, "percentage": 15}                        |
+---------------------------------------------------------------------+

如果您不想(或不能)使用规范化数据集,那么也许您可能会考虑编写一个存储过程,该过程循环遍历您的详细信息列并聚合每个列的数据,并使用查询聚合两个数据集。

【讨论】:

  • 如果您必须处理作为 JSON 数组的单个结果集,则可以使用另一个带有 JSON_ARRAY 的外部查询。
  • 如此精美的解释和格式化的答案。谢谢你。
【解决方案2】:

鉴于数据似乎在每个实例中都具有相同的列,因此根本不清楚您为什么要使用 JSON。您没有描述为什么不能使用传统列而不是 JSON 的任何原因。

JSON 数组应存储在第二个表的多行中。

CREATE TABLE `SampleDetails` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `sample_id` INT NOT NULL,
  `name` VARCHAR(10) NOT NULL,
  `amount` DECIMAL(9,2) NOT NULL,
  `percentage` TINYINT NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO SampleDetails (sample_id, name, amount, percentage) VALUES
(1, 'T1', 34.34, 45},
(3, 'T3', 30.34, 45},
(2, 'T2', 14.34, 15}
(1, 'T1', 34.34, 45},
(2, 'T2', 30.34, 45},
(4, 'T4', 14.34, 15);

然后你可以使用非常简单的 SQL 来得到总和:

SELECT sample_id, MAX(name) AS name, 
  SUM(amount) AS amount, MAX(percentage) AS percentage
FROM SampleDetails
GROUP BY sample_id;

将该 SQL 查询的结果提取到您的应用程序中,然后将其格式化为 JSON。每种语言都有一个用于读写 JSON 的包。

【讨论】:

    【解决方案3】:

    创建自己的mysql函数怎么样?

    create function x_json_sum (json_object varchar(5000), json_path varchar(5000))
    returns int deterministic
    begin
      declare output int default 0;
      declare i int default 0;
      while json_extract(json_object, concat(json_path, '[', i,']')) is not null do
        set output = output + json_extract(json_object, concat(json_path, '[', i,']'));
        set i = i + 1;
      end while;
      return output;
    end;
    

    结果

    MariaDB [****]> select x_json_sum('{"money": [3, 4, 3]}', '$.money');
    +-----------------------------------------------+
    | x_json_sum('{"money": [3, 4, 3]}', '$.money') |
    +-----------------------------------------------+
    |                                            10 |
    +-----------------------------------------------+
    1 row in set (0.00 sec)
    

    我刚刚编写了这个函数,它适用于我的示例。您可能需要进行更多验证,例如何时返回 null?数据会被截断吗?功能安全和定义器?等等

    您也可以结合这个 sum 函数并创建其他函数,例如 x_json_avg 等。

    【讨论】:

    • 谢谢我的情况非常相似,这个例子非常有用
    【解决方案4】:

    您可以在此处使用 ETL 将 jason 提取到 sql,然后将 SQL 查询应用到 Aggregate

    【讨论】:

    • 你能把这个示例查询发给我吗?我不太擅长 ETL
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多