mysql 计算12个月每月值以及每月累加值(利用临时变量 )

1.表结构
在这里插入图片描述
简单的月份对应值的结构~

2.计算累加值后的结果
在这里插入图片描述
value_acc就是计算得到的累加列~

3.具体方法

SELECT date,value, @tempvar:=@tempvar+value
FROM test_tb,(SELECT @tempvar:=0)T
ORDER BY date DESC

只需关注@tempvar这个临时变量就可以,(SELECT @tempvar:=0)T 是个临时表T,这个表里选出了赋有初值0的临时变量,每次select时,该临时变量都累加当前value,就形成累加列了~

<think>我们想要获取上个的第一天到最后一天的所有数据。首先,我们需要确定上个的第一天和最后一天。 思路: 1. 获取当前日期。 2. 计算上个的第一天:将当前日期减去一个,然后设置为该的第一天。 3. 计算上个的最后一天:将上个的第一天加上一个,然后减去一天。 4. 使用BETWEEN条件在查询中筛选日期字段。 但是,注意:如果当前日期是1,那么上个就是去年的12。 在MySQL中,我们可以使用以下函数: - CURDATE():获取当前日期。 - DATE_SUB():日期减法。 - DATE_ADD():日期加法。 - LAST_DAY():获取某个的最后一天。 - 使用DATE_FORMAT()来构造一个的第一天。 步骤: 方法1: 上个的第一天:我们可以将当前日期减去一个,然后使用DATE_FORMAT将其格式化为该的第一天,例如: DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01') 或者,也可以这样: DATE_SUB(DATE_SUB(CURRENT_DATE, INTERVAL DAY(CURRENT_DATE)-1 DAY), INTERVAL 1 MONTH) 方法2(更简单): 上个第一天:DATE_ADD(LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 2 MONTH)), INTERVAL 1 DAY) 上个最后一天:LAST_DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) 但是,更简单的方式是: 上个第一天:DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01') 上个最后一天:LAST_DAY(CURRENT_DATE - INTERVAL 1 MONTH) 注意:CURRENT_DATE - INTERVAL 1 MONTH 得到的是上个的同一天(如果当前是330日,则得到228日或29日,取决于是否是闰年),但我们需要的是上个的第一天和最后一天。 因此,我们可以这样: 设:start_date = DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01') 然后:end_date = LAST_DAY(start_date) 或者直接: start_date = DATE_ADD(LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 2 MONTH)), INTERVAL 1 DAY); end_date = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)); 但是,更简单且直观的是: start_date = LAST_DAY(CURDATE() - INTERVAL 2 MONTH) + INTERVAL 1 DAY; end_date = LAST_DAY(CURDATE() - INTERVAL 1 MONTH); 但是,在MySQL中,日期加减可以直接用INTERVAL,但是注意:LAST_DAY函数返回的是该的最后一天,然后我们可以通过加1天得到下个的第一天,但这里我们需要上个的第一天。 因此,我们采用: 上个第一天:concat(date_format(date_sub(curdate(), interval 1 month),'%Y-%m'),'-01') 上个最后一天:last_day(date_sub(curdate(), interval 1 month)) 所以,查询语句可以写成: SELECT * FROM your_table WHERE your_date_column BETWEEN concat(date_format(date_sub(curdate(), interval 1 month),'%Y-%m'),'-01') AND last_day(date_sub(curdate(), interval 1 month)); 但是,注意:如果your_date_column包含时间部分,那么BETWEEN会包括最后一天的00:00:00,但不会包括最后一天的23:59:59之后的时间。因此,更安全的做法是: WHERE your_date_column >= concat(date_format(date_sub(curdate(), interval 1 month),'%Y-%m'),'-01') AND your_date_column < last_day(date_sub(curdate(), interval 1 month)) + interval 1 day 或者,我们可以将上个最后一天的时间设置为23:59:59,但这样可能不够优雅,因为数据库中的时间可能是精确到毫秒的。所以,通常使用小于下个第一天的方式。 因此,改进: start_date = concat(date_format(date_sub(curdate(), interval 1 month),'%Y-%m'),'-01') next_month_first_day = last_day(date_sub(curdate(), interval 1 month)) + interval 1 day 然后:WHERE your_date_column >= start_date AND your_date_column < next_month_first_day 这样,所有小于下个第一天的数据都会被包括,即包括上个最后一天的23:59:59.999。 所以,完整的查询语句: SELECT * FROM your_table WHERE your_date_column >= concat(date_format(date_sub(curdate(), interval 1 month),'%Y-%m'),'-01') AND your_date_column < last_day(date_sub(curdate(), interval 1 month)) + interval 1 day; 但是,我们也可以使用另一种方式获取上个第一天: date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month) 解释:先获取这个的第一天(当前日期减去(当前日期的天数-1)天),然后减去一个,就是上个的第一天。 所以,也可以这样写: SELECT * FROM your_table WHERE your_date_column >= date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month) AND your_date_column < date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 0 month); 注意:date_sub(curdate(), interval day(curdate())-1 day) 得到的是这个的第一天,然后减去一个就是上个的第一天。 而小于这个的第一天,就是上个的最后一天之后(即不包括这个第一天,但包括上个最后一天)?不对,我们想要的是上个整个。 所以,这个的第一天就是上个最后一天的下一天。因此,我们可以这样: WHERE your_date_column >= date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month) AND your_date_column < date_sub(curdate(), interval day(curdate())-1 day); 这样,条件就是:大于等于上个第一天,小于这个的第一天(即上个最后一天的下一天)。 这种方法更简洁,而且不需要使用字符串拼接。 因此,我们采用这种方式: SELECT * FROM your_table WHERE your_date_column >= (date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month)) AND your_date_column < (date_sub(curdate(), interval day(curdate())-1 day)); 但是,注意:这样计算的是上个,而且不受份天数不同的影响。 示例:假设当前日期是2023-03-15。 计算这个的第一天:2023-03-01(当前日期减去14天) 上个第一天:2023-03-01减去1个,得到2023-02-01。 条件:>=2023-02-01 且 <2023-03-01,这样正好是2份的所有数据。 所以,这个方法是可行的。 但是,如果当前日期是2023-01-15,那么: 这个的第一天:2023-01-01 上个第一天:2023-01-01减去1个,得到2022-12-01。 条件:>=2022-12-01 且 <2023-01-01,这样就是2022年12的数据。 因此,这个逻辑是通用的。 所以,我们推荐使用这种方法。 但是,如果表中数据量很大,且your_date_column有索引,那么使用这个条件可以高效利用索引。 因此,最终的查询语句: SELECT * FROM your_table WHERE your_date_column >= (SELECT date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month)) AND your_date_column < (SELECT date_sub(curdate(), interval day(curdate())-1 day)); 注意:这里我们使用了子查询来避免重复计算,但实际上MySQL优化器可能会优化,我们也可以将这两个计算出来然后作为条件。 或者,我们可以先计算这两个,然后在查询中使用变量。但是,在一条语句中,我们可以直接使用表达式,因为表达式是确定的。 所以,也可以这样: SET @start_date = date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month); SET @end_date = date_sub(curdate(), interval day(curdate())-1 day); SELECT * FROM your_table WHERE your_date_column >= @start_date AND your_date_column < @end_date; 但是,如果要在一条语句中完成,我们可以不使用变量,直接使用表达式。 因此,我们写: SELECT * FROM your_table WHERE your_date_column >= date_sub(date_sub(curdate(), interval day(curdate())-1 day), interval 1 month) AND your_date_column < date_sub(curdate(), interval day(curdate())-1 day); 注意:这个查询假设你的表中有一个日期字段(your_date_column),你需要将其替换为实际的字段名。 另外,如果表中数据量很大,建议使用索引,这个条件可以很好地使用索引。 但是,如果担心性能,也可以将这两个日期先计算出来,然后作为常量传入,这样就不需要在每一行都计算表达式。 不过,在MySQL中,这种确定性函数通常会被优化,只计算一次。 所以,我们使用上述查询。 但是,还有一种更简洁的方法:使用`MAKEDATE`和`MAKEDATE`结合,但这里我们使用的方法已经比较清晰。 另外,也可以使用`PERIOD_DIFF`等函数,但可能更复杂。 因此,我们采用上述方法。 总结:查询上个的所有数据,使用条件为日期字段大于等于上个第一天,小于这个第一天。 注意:如果your_date_column是DATETIME类型,那么条件中的日期会被当作'YYYY-MM-DD 00:00:00',所以小于这个第一天,就是小于'YYYY-MM-01 00:00:00',这样正好包括上个最后一天的23:59:59.999。 所以,这个查询是安全的。 现在,我们写出完整的查询语句。</think>要获取上个第一天到最后一天的全部数据,可以使用以下MySQL查询语句: ```sql SELECT * FROM your_table WHERE your_date_column BETWEEN DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01') AND LAST_DAY(CURRENT_DATE - INTERVAL 1 MONTH); ``` ### 关键函数说明: 1. `CURRENT_DATE - INTERVAL 1 MONTH` 获取上个的当前日期(如今天是2023-08-15,则返回2023-07-15) 2. `DATE_FORMAT(date, '%Y-%m-01')` 将日期格式化为该的第一天(如2023-07-15 → 2023-07-01) 3. `LAST_DAY(date)` 返回该的最后一天(如2023-07-15 → 2023-07-31) ### 注意事项: 1. 替换以下占位符: - `your_table`:您的表名 - `your_date_column`:您的日期字段名 2. 如果日期字段包含时间部分,改用范围查询避免遗漏: ```sql SELECT * FROM your_table WHERE your_date_column >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01') AND your_date_column < DATE_FORMAT(CURRENT_DATE, '%Y-%m-01'); ``` ### 示例说明: 假设今天是2023-08-15,查询逻辑: 1. 上个第一天:`DATE_FORMAT('2023-07-15', '%Y-%m-01') = 2023-07-01` 2. 上个最后一天:`LAST_DAY('2023-07-15') = 2023-07-31` 3. 最终查询范围:`2023-07-01 00:00:00` 到 `2023-07-31 23:59:59` ### 跨年处理: 该方案自动处理跨年情况(如2023-01-15会返回2022-12-01至2022-12-31的数据),无需额外调整[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值