奇怪的 SQL

SQL查询技巧:时间计算与数据统计
本文介绍了SQL查询中的时间处理方法,包括计算回复时间的差异,创建虚拟表来展示近几个月的数据分布,以及如何进行两个日期间的数据统计。通过CASE语句和BETWEEN操作符,实现了灵活的时间间隔表达和数据统计分析。


一、DQL(查询)

1-1】计算回复时间

# 例如:三天前回复了我,我却把他搁置了
CASE
    WHEN TIMESTAMPDIFF(MINUTE, b.create_date, now()) < 5 THEN '刚刚'
    WHEN TIMESTAMPDIFF(MINUTE, b.create_date, now()) < 60 THEN CONCAT(TIMESTAMPDIFF(MINUTE, b.create_date, now()),'分钟前')
    WHEN TIMESTAMPDIFF(HOUR, b.create_date, now()) < 24 THEN CONCAT(TIMESTAMPDIFF(HOUR, b.create_date, now()),'小时前')
    WHEN TIMESTAMPDIFF(DAY, b.create_date, now()) < 31 THEN CONCAT(TIMESTAMPDIFF(DAY, b.create_date, now()),'天前')
    WHEN TIMESTAMPDIFF(MONTH, b.create_date, now()) < 12 THEN CONCAT(TIMESTAMPDIFF(MONTH, b.create_date, now()),'月前')
    ELSE CONCAT(TIMESTAMPDIFF(YEAR, b.create_date, now()),'年前')
END as time,

1-2】最近几个时间阶段虚拟表

# 例如查询近七天,近 12 个月的数据
SELECT
     DATE_FORMAT(a.t,'%Y-%c') as time,
     COUNT(t.id) as sum
 FROM
     (
         SELECT now() as t union
         SELECT DATE_SUB(now(), INTERVAL + 1 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 2 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 3 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 4 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 5 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 6 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 7 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 8 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 9 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 10 MONTH) as t union
         SELECT DATE_SUB(now(), INTERVAL + 11 MONTH) as t
     ) a
 LEFT JOIN table t
     ON MONTH(t.create_date) = MONTH(a.t)
     AND TIMESTAMPDIFF(YEAR, t.create_date, now()) < 1
     AND IF(MONTH(t.create_date)=MONTH(NOW()), YEAR(t.create_date)=YEAR(NOW()), 1=1)
 GROUP BY MONTH(a.t)
 ORDER BY a.t

1-3】两个日期间的数据统计

BETWEEN 也许会更好

// 使用 java 代码帮助实现,这边为工具类下的方法

/**
 * 获取两个日期中所有天
 *
 * @param startTime 开始时间
 * @param endTime   结束时间
 * @param include   是否包含结束时间
 * @return List<Date> 格式 +2:[ ]、[ )
 */
public static List<Date> betweenDayInclude(Date startTime, Date endTime, Boolean include) {
    List<Date> returnList = new ArrayList<>();

    Calendar start = Calendar.getInstance();
    start.setTime(startTime);
    Calendar end = Calendar.getInstance();
    end.setTime(endTime);
    /*
        避免出现 开始时间 为当天日出的同时 结束日间 为日落时分
        第一阶段:判断出不是同一天,是过去的天 ✓
        第二阶段:同一天进行判断 开始时间 依旧是 结束时间的前面 ✗
        总结:这是个 bug,得排除
     */
    end.set(end.get(Calendar.YEAR), end.get(Calendar.MONTH), end.get(Calendar.DATE), 0, 0, 0);

    while (start.before(end)) {
        returnList.add(start.getTime());
        start.add(Calendar.DAY_OF_YEAR, 1);
    }
    if (Boolean.TRUE.equals(include)) {
        returnList.add(end.getTime());
    }
    return returnList;
}
SELECT
	DATE_FORMAT(b.t,'%m.%e') as time,
	b.*
from 
	(
		<foreach item="l" collection="list" open="" separator=" union " close="">
			select #{l} as t
		</foreach>
	) a
left join table_b b on TIMESTAMPDIFF(DAY, b.create_date, a.t) = 0
GROUP BY DAY(a.t)
order by DAY(a.t)
### 解决SQL语句中异常空格的问题 #### 使用替换函数去除多余空格 在处理 SQL 语句中的异常空格时,可以利用数据库内置的字符串操作函数来清理这些不必要的字符。对于大多数关系型数据库管理系统 (RDBMS),提供了诸如 `REPLACE` 函数用于替代指定子串。 针对特定情况下的全角空格或其他不可见字符,可先识别其 ASCII 或 Unicode 编码值再做相应转换: ```sql SELECT REPLACE(REPLACE(your_column, CHAR(160), ''), ' ', '') AS cleaned_text FROM your_table; ``` 此命令将把字段内的所有半角 (`' '` 对应 ASCII 32) 全角空格(HTML 实体   对应 ASCII 160)都移除[^4]。 #### 利用正则表达式匹配复杂模式 部分高级 RDBMS 支持更强大的正则表达式功能来进行复杂的文本清洗工作。例如,在 PostgreSQL 中可以直接应用 regex_replace 来完成任务;而在 MySQL 8.0 及以上版本也引入了 REGEXP_REPLACE 方法支持相似的功能。 下面给出一个基于 MySQL 的例子,它不仅能够清除常规空白符还能过滤掉其他类型的控制字符: ```sql UPDATE your_table SET your_column = TRIM(REGEXP_REPLACE(your_column, '[\\s[:cntrl:]]+', '')); ``` 这段代码会删除列内所有的连续空白以及任何属于 "control characters" 类别的符号,并保留单个标准间隔作为分隔标志。 #### 数据预处理阶段预防性措施 除了事后修正已存在的数据外,在应用程序层面采取适当策略同样重要。比如编写自定义验证逻辑确保输入合法性,或是借助 ORM 框架提供的工具自动规范化待入库的数据集等手段都可以有效减少此类错误的发生几率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值