【问题标题】:JSON Insert into a MySQL table or update if existsJSON 插入 MySQL 表或更新(如果存在)
【发布时间】:2018-05-10 11:04:20
【问题描述】:

这是Insert into a MySQL table or update if exists的延续,不过这次我要更新mysql中的json条目

下面是架构:

CREATE TABLE TAG_COUNTER (
    account       varchar(36) NOT NULL,
    time_id       INT NOT NULL,
    counters      JSON,
    PRIMARY KEY   (account, time_id)
)

示例数据如下所示。

'google', '20180510', '{"gmail_page_viewed" : 12000300, "search_page_viewed" : 9898884726423}'

其实我一直想更新(增加计数器)这个表。但是每天开始时间_id(yyyyMMdd)都是新的,因此计数器json没有计数器键(例如gmail_page_viewed)。


所以我想要的解决方案是在不存在时使用
value = 1 创建新的 json 键列。例如{"gmail_page_viewed" : 1}


如果计数器(例如gmail_page_viewed)键存在,则增加
value = value + 1

如果 json 计数器存在,请帮助我进行插入查询并进行更新。

UPDATE_1(信息:使用 json 时始终使用 IFNULL)

我使用了@wchiquito 建议的解决方案,但看到了以下问题。

第一次(架构创建后);试过下面的sql

  INSERT INTO `TAG_COUNTER`
  (`partner_id`, `time_id`, `counters`)
VALUES
  ('google', '20180510', '{"gmail_page_viewed": 1}')
ON DUPLICATE KEY UPDATE `counters` =
  JSON_SET(`counters`,
           '$.gmail_page_viewed',
           JSON_EXTRACT(`counters`,
                        '$.gmail_page_viewed') + 1
  );

并得到以下响应;正如预期的那样正确。

'google', '20180510', '{"gmail_page_viewed": 1}'

然后在下一个查询中尝试使用不同的计数器,

  INSERT INTO `TAG_COUNTER`
  (`account`, `time_id`, `counters`)
VALUES
  ('google', '20180510', '{"search_page_viewed": 1}')
ON DUPLICATE KEY UPDATE `counters` =
  JSON_SET(`counters`,
           '$.search_page_viewed',
           JSON_EXTRACT(`counters`,
                        '$.search_page_viewed') + 1
  );

并得到了以下内容。

'google', '20180510', '{"gmail_page_viewed": 1, "search_page_viewed": null}'  

知道为什么这个新的计数器 search_page_viewed 设置为 NULL ..?

UPDATE_2(信息:当数字用作键时,在键周围使用双引号)

我也遇到过以下问题,并从那个答案中解决了

Mysql 5.7 ERROR 3143 (42000): Invalid JSON path expression. The error is around character position 3

UPDATE_3(信息:分组依据,使用“NOT NULL”或“> 0”确保 WHERE

获取每个时间范围内的计数(例如,按日、月、年)

  SELECT 
  SUBSTRING(time_id, 1, 6) AS month, 
  SUM(counters->>'$.gmail_page_viewed') 
  FROM TAG_COUNTER 
  WHERE counters->>'$.gmail_page_viewed' > 0
  GROUP BY month;

UPDATE_4(问题:)

我想查看每次(小时/天/月/年)的趋势页面 从下面的查询中,我可以获得每次计数,但前提是我知道密钥(gmail_page_viewed)。

  SELECT 
  SUBSTRING(time_id, 1, 6) AS month, 
  SUM(counters->>'$.gmail_page_viewed') 
  FROM TAG_COUNTER 
  WHERE counters->>'$.gmail_page_viewed' > 0
  GROUP BY month;

但我想要的是如何知道每次页数的总体趋势?所以我需要类似下面的东西,请帮忙。

group by SUBSTRING(time_id, 1, 6) AS month, KEY
order by SUM(counters->>'$.KEY') 

【问题讨论】:

  • 我不确定我是否真的理解你的要求,但是,下面的脚本可以给你一些想法,见dbfiddle
  • @wchiquito 太棒了!一个问题你已经更新了gmail_page_viewed但没有更新search_page_viewed?在这种情况下如何更新两者?
  • 查看更新的dbfiddle
  • @wchiquito 太棒了!这就是我想要的。谢谢!非常。您能否将其添加为下面的答案,以便我接受?
  • ... SUM(IFNULL(counters->>'$."gmail_page_viewed"', 0)) ...... IFNULL(counters->>'$."gmail_page_viewed"', 0) > 0 ...

标签: mysql json


【解决方案1】:

以下脚本可以满足您的要求:

INSERT INTO `TAG_COUNTER`
  (`account`, `time_id`, `counters`)
VALUES
  ('google', '20180510', '{"gmail_page_viewed": 1, "search_page_viewed": 50}'),
  ('google', '20180510', '{"gmail_page_viewed": 1, "search_page_viewed": 50}'),
  ('google', '20180511', '{"gmail_page_viewed": 1, "search_page_viewed": 100}'),
  ('google', '20180511', '{"gmail_page_viewed": 1, "search_page_viewed": 100}'),
  ('google', '20180511', '{"gmail_page_viewed": 1, "search_page_viewed": 100}')
ON DUPLICATE KEY UPDATE `counters` =
  JSON_SET(`counters`,
           '$."gmail_page_viewed"',
           IFNULL(`counters` ->> '$."gmail_page_viewed"', 0) + 1,
           '$."search_page_viewed"',
           IFNULL(`counters` ->> '$."search_page_viewed"', 0) + 1
  );

dbfiddle

【讨论】:

  • 我在遵循解决方案时看到了不同的问题。你能帮忙更新一下吗..?
  • @KanagaveluSugumar:记得根据需要调整脚本,见更新dbfiddle
猜你喜欢
  • 2011-05-11
  • 1970-01-01
  • 2016-08-23
相关资源
最近更新 更多