如何正确使用SQL中的WHERE运算符?以及如何实现9-18点15分钟间隔统计?
咱们先从最基础的用法说起,WHERE是用来过滤SQL查询结果的核心子句,它会在查询返回数据前筛选出符合条件的行。下面是一些关键的使用要点:
基础比较操作:用常见的比较运算符匹配值,比如等于
=、不等于!=/<>、大于>、小于<、大于等于>=、小于等于<=。举个例子,筛选订单金额大于100的记录:SELECT * FROM orders WHERE amount > 100;逻辑组合条件:用
AND、OR、NOT把多个条件组合起来。注意优先级:NOT最高,然后AND,最后OR,不确定顺序的时候用括号明确。比如筛选2023年的订单且金额大于100:SELECT * FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01' AND amount > 100;处理NULL值:普通比较运算符对
NULL不起作用,必须用IS NULL或IS NOT NULL判断。比如筛选未填写收货地址的用户:SELECT * FROM users WHERE shipping_address IS NULL;匹配多个值:用
IN匹配某个集合里的值,比多个OR更简洁。比如筛选来自北京、上海、广州的用户:SELECT * FROM users WHERE city IN ('北京', '上海', '广州');模糊匹配:用
LIKE配合通配符%(匹配任意长度字符)和_(匹配单个字符)。比如筛选名字以“张”开头的用户:SELECT * FROM users WHERE username LIKE '张%';性能注意事项:如果查询涉及大表,尽量让
WHERE子句的条件能用到索引——比如避免在列上做函数运算(WHERE YEAR(order_date) = 2023会让索引失效,换成order_date BETWEEN '2023-01-01' AND '2023-12-31'更优)。
你的需求是统计09:00到18:00之间按15分钟间隔分组的数据,现有SQL已经有了核心逻辑,但临时表inter的定义不完整。咱们补全并优化这个查询:
第一步:补全原始SQL的临时表inter
首先,inter需要定义目标时间段的起始秒数、结束秒数,以及间隔宽度(15分钟=900秒)。09:00转换为秒是9*3600=32400,18:00是18*3600=64800:
SELECT t.event_date, case when TIME_TO_SEC(t.event_date) > inter.begin AND TIME_TO_SEC(t.event_date) < inter.end then floor((TIME_TO_SEC(t.event_date) - inter.begin) / inter.width) when TIME_TO_SEC(t.event_date) <= inter.begin then 0 when TIME_TO_SEC(t.event_date) >= inter.end then floor((inter.end - inter.begin) / inter.width) else null end as full_interval_number FROM `table` t, (select 32400 as begin, -- 09:00对应的秒数 64800 as end, -- 18:00对应的秒数 900 as width -- 15分钟=900秒 ) inter;
第二步:简化逻辑(更简洁的写法)
上面的CASE可以简化,先把超出09:00-18:00的时间“截断”到区间内,再计算间隔编号:
SELECT t.event_date, FLOOR( GREATEST( LEAST(TIME_TO_SEC(t.event_date), 64800) - 32400, 0 ) / 900 ) AS full_interval_number FROM `table` t;
这里LEAST把晚于18:00的时间截断到64800秒,GREATEST把早于09:00的时间截断到0秒,直接除以900取整就能得到间隔编号,逻辑更清晰。
第三步:扩展为统计每个间隔的记录数(常见需求)
如果你的最终目标是统计每个15分钟间隔内的记录数量,可以在此基础上分组:
SELECT -- 把间隔编号转换为可读的时间段 SEC_TO_TIME(32400 + full_interval_number * 900) AS interval_start, SEC_TO_TIME(32400 + (full_interval_number + 1) * 900) AS interval_end, COUNT(*) AS record_count FROM ( SELECT FLOOR( GREATEST( LEAST(TIME_TO_SEC(event_date), 64800) - 32400, 0 ) / 900 ) AS full_interval_number FROM `table` ) AS interval_groups GROUP BY full_interval_number ORDER BY full_interval_number;
这样就能得到每个15分钟间隔的起始时间、结束时间和对应的记录数了。
内容的提问来源于stack exchange,提问作者Vika Smirnova

