MySQL是否存在可从序列中任选值的聚合函数?股票查询场景
解决方案:替代MIN()选取任意值的SQL方法
嘿,针对你在股票分析SQL查询里遇到的两个聚合函数问题,我给你整理了几个精准的替代方案,完全满足你“选取任意值”的需求,而且比用MIN()更贴合场景、效率更高:
1. 针对low_table.low字段(所有值相同)
因为你提到这个字段在分组内的所有值都是一致的,除了用MIN(),你有两个更合适的选择:
ANY_VALUE()函数(MySQL 5.7及以上版本支持):这是MySQL专门为这类场景设计的函数,直接从分组中返回任意一个值,不需要进行任何计算,完美匹配你的需求。修改后的字段写法是:ANY_VALUE(low_table.low)- 直接将字段加入GROUP BY:由于分组内该字段值完全相同,把它加到GROUP BY子句里后,SELECT子句可以直接写
low_table.low,不需要任何聚合函数。
2. 针对sh.trading_date字段(需要任意一个日期值)
同样,ANY_VALUE()是最优解,它会从分组的所有日期中随机返回一个,不需要计算最小/最大值,节省不必要的运算。替代后的写法是:ANY_VALUE(sh.trading_date)
如果你使用的是MySQL 8.0及以上版本,还可以用窗口函数来实现更灵活的取值,同时避免GROUP BY的聚合逻辑,比如用ROW_NUMBER()给每个股票的符合条件的记录标记序号,然后取第一条(序号为1的记录),示例SQL如下:
WITH ranked_data AS ( SELECT s.symbol, sh.trading_date, low_table.low, -- 这里ORDER BY可以随便指定,或者写ORDER BY NULL取任意记录 ROW_NUMBER() OVER(PARTITION BY s.symbol ORDER BY sh.trading_date) AS rn FROM ( SELECT stock_id, MIN(close) AS low FROM stocks_stockhistory WHERE trading_date >= '2017-05-04' GROUP BY stock_id ) AS low_table JOIN stocks_stockhistory AS sh ON sh.stock_id = low_table.stock_id AND sh.close = low_table.low JOIN stocks_stock AS s ON sh.stock_id = s.id WHERE sh.trading_date >= '2018-04-30' ) SELECT symbol, trading_date, low FROM ranked_data WHERE rn = 1 ORDER BY symbol ASC;
修改后的原查询版本
用ANY_VALUE()替换MIN()后的最终SQL如下,既满足去重需求,又避免了多余的聚合计算:
SELECT s.symbol, ANY_VALUE(sh.trading_date), ANY_VALUE(low_table.low) FROM ( SELECT stock_id, min(close) as low FROM stocks_stockhistory WHERE trading_date >= '2017-05-04' GROUP BY stock_id ) as low_table, stocks_stockhistory as sh, stocks_stock as s WHERE sh.stock_id = low_table.stock_id AND sh.stock_id = s.id AND sh.close = low_table.low AND sh.trading_date >= '2018-04-30' GROUP BY s.symbol ORDER BY s.symbol asc;
内容的提问来源于stack exchange,提问作者Saqib Ali
相关产品推荐
相关产品推荐

