同样是 MySQL 8,这个我问题我硬是没搞明白会这样,希望大家帮我分析一下

2022-03-25 14:31:10 +08:00
 CyJaySong

有一个表

CREATE TABLE `trade_account_total_daily_record`
(
    `date`         date           NOT NULL COMMENT '日期',
    `account_type` int            NOT NULL COMMENT '账户类型',
    `balance`      decimal(20, 2) NOT NULL DEFAULT 0.00 COMMENT '账户余额',
    `created_at`   datetime       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `updated_at`   datetime       NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    PRIMARY KEY (`date`, `account_type`)
) ;

我执行

SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d'), 1, IFNULL(SUM(balance),0) + 10
FROM trade_account_total_daily_record WHERE account_type = 1 ORDER BY date DESC LIMIT 1 

能正确给出结果, 但是执行

INSERT INTO trade_account_total_daily_record (`date`, `account_type`, `balance`)
SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d'), 1, IFNULL(SUM(balance),0) + 10
FROM trade_account_total_daily_record WHERE account_type = 4 ORDER BY date DESC LIMIT 1
ON DUPLICATE KEY UPDATE `balance`=VALUES(`balance`) 

就报 Column 'date' cannot be null ,奇怪的是阿里云 RDS 数据库(mysql-8.0.25)会这样,我本地的 8.0.28 没问题

2901 次点击
所在节点    MySQL
34 条回复
CyJaySong
2022-03-25 15:21:04 +08:00
在套一个 SELECT 就可以了。。。好奇怪
```
INSERT INTO trade_account_total_daily_record (`date`, `account_type`, `balance`)
SELECT tmp.* FROM(SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d'), 4, IFNULL(SUM(balance),0) + 10
FROM trade_account_total_daily_record AS tmp WHERE account_type = 4 ORDER BY date DESC LIMIT 1) AS tmp
ON DUPLICATE KEY UPDATE `balance`=VALUES(`balance`)
```
wps353
2022-03-25 15:30:26 +08:00
检查一下 sql_mode 。
westoy
2022-03-25 15:32:51 +08:00
ORDER BY date => ORDER BY `date`试试?
CyJaySong
2022-03-25 16:00:44 +08:00
@wps353 看了一下,阿里云和本地的一样
CyJaySong
2022-03-25 16:01:24 +08:00
@westoy 还是一样
CyJaySong
2022-03-25 16:06:58 +08:00
之前那种销量很低,子查询居然全表查询了,换成这种更好
INSERT INTO trade_account_total_daily_record (`date`, `account_type`, `balance`)
SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d'), 4, IFNULL(SUM(tmp.balance),0) + 10,FROM (SELECT balance FROM trade_account_total_daily_record WHERE account_type = 4 ORDER BY `date` DESC LIMIT 1) AS tmp
ON DUPLICATE KEY UPDATE `balance`=VALUES(`balance`)
northernlights0
2022-03-25 16:22:23 +08:00
搞不好是 RDS 的 bug 。阿里云数据库并不是简单地跑一个 mysql 实例给你用,为了利用好资源,底层有很多他们自己实现的东西,甚至可能查询引擎都和 mysql 默认的不一样。
jtwor
2022-03-25 16:37:28 +08:00
是不是 DATE_FORMAT 转成的是字符串 而不是 date 类型报的?
encro
2022-03-25 16:40:26 +08:00
这么简单的问题。。。。。
错误提示这么明显了。。。

PRIMARY KEY (`date`, `account_type`) 重复了。。。。。
encro
2022-03-25 16:40:49 +08:00
SELECT DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d'), 1, IFNULL(SUM(balance),0) + 10
FROM trade_account_total_daily_record WHERE account_type = 1 ORDER BY date DESC LIMIT 1


这条语句写的莫名其妙。
encro
2022-03-25 16:43:10 +08:00
sorry 是我看错了。
encro
2022-03-25 16:45:58 +08:00
DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d') 直接换成 CURRENT_DATE 试试?
encro
2022-03-25 16:52:07 +08:00
mysql replace into 应该比你这个更好用。
SUM(balance) + LIMIT 1 我看不出这是想干啥?

看起来希望:

replace into trade_account_total_daily_record set `balance`=balance+10 where date=CURRENT_DATE and account_type = 4 ORDER BY date DESC LIMIT 1
CyJaySong
2022-03-25 16:53:17 +08:00
@encro 确实有性能问题,EXPLAIN 显示全表查询了。用#6 那种就不会了
CyJaySong
2022-03-25 16:59:48 +08:00
@encro 回复#13 ,不是为了替换,这个表主要是统计每个账户类型的每日总日结余额,每次资金变动时,更新总日结余额。
encro
2022-03-25 17:07:42 +08:00
哈哈,你需要一个物化视图。
果然 pg 才是最好选择。
encro
2022-03-25 17:08:47 +08:00
replace into trade_account_total_daily_record set `balance`=balance+10 where date=CURRENT_DATE and account_type = 4

更新日结用我这个就可以了。
CyJaySong
2022-03-25 17:23:43 +08:00
@encro 回复#17 : REPLACE INTO 效率没得 ON DUPLICATE KEY UPDATE 高,而且你这句没达到我要的目的🤣
CyJaySong
2022-03-25 17:25:19 +08:00
@northernlights0 回复#7 大概是吧,不过通过多套一个子查询解决了,反而提高了性能
CyJaySong
2022-03-25 17:26:18 +08:00
@jtwor 回复#8 问题不在这儿,大概如#7 说的那样

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/842853

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX