我有一个大型数据库,用于绘图和数据检查。为简单起见,请说它看起来像这样:
| id | day | obs |
+----------+-----------+-----------+
| 1 | 500 | 4.5 |
| 2 | 500 | 4.4 |
| 3 | 500 | 4.7 |
| 4 | 500 | 4.8 |
| 5 | 600 | 5.1 |
| 6 | 600 | 5.2 |
...
这可能是股票市场数据,我们每天测量的点数很多。
我想要做的是查看更长的趋势,每天多个点被不必要地解决,并堵塞我的绘图应用程序。 (我想看看30000天,每次都有大约100次观察)。
有没有办法做SELECT ... LIMIT 1 PER "day"
我想我可以执行一些SELECT DISTINCT
查询来查找正确的ID,但如果是内置的,我宁愿做一些简单的事情。
无论是每天的第一个,最后一个还是平均值,都无关紧要。只是一个值。我只是喜欢最快的。
另外,我想为Postgres,MySQL和SQLite做这个。我的应用程序是为了使用这三个而构建的,我经常在它们之间切换。
谢谢!
背景:这是针对Ruby on Rails绘图应用程序的,因此使用ActiveRecord的技巧也可以。 https://github.com/ZachDischner/Rails-Plotter
答案 0 :(得分:3)
您需要使用您正在使用的RDBMS品牌标记您的问题。对于Rails开发人员来说,他们经常使用MySQL,但问题的答案取决于此。
对于除MySQL之外的所有品牌,正确和标准的解决方案是使用窗口函数:
SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY day) AS RN, *
FROM stockmarketdata
) AS t
WHERE t.RN = 1;
对于不支持窗口函数的MySQL,你可以用会话变量以一种笨拙的方式模拟它们:
SELECT * FROM (SELECT @day:=0, @r:=0) AS _init,
(
SELECT IF(day=@day, @r:=@r+1, @r:=0) AS RN, @day:=day AS d, *
FROM stockmarketdata
) AS t
WHERE t.RN = 1
答案 1 :(得分:1)
您的陈述留下了很多选择空间:
无论是每天的第一个,最后一个还是平均值,都无关紧要。只是一个值。我只是喜欢最快的。
所以,我要将id从它中删除并首先建议将每个组的平均值作为最简单且可能最实用的,但可能不是运行stat函数与限制的最快速度:
MyModel.group(:day).average(:obs)
如果你想要最低限度:
MyModel.group(:day).minimum(:obs)
如果你想要最大值:
MyModel.group(:day).maximum(:obs)
(注意:以下两个示例的效率低于仅输入SQL,但可能更具可移植性。)
但你可能想要这三个:
ActiveRecord::Base.connection.execute(MyModel.select('MIN(obs), AVG(obs), MAX(obs)').group(:day).to_sql).to_a
或者只是没有哈希的数据:
ActiveRecord::Base.connection.exec_query(MyModel.select('MIN(obs), AVG(obs), MAX(obs)').group(:day).to_sql)
如果您想要中位数,请参阅this question哪个更具有数据库功能,如果您搜索,还有其他相关的posts。
而更多,某些数据库就像postgres有variance(...)
,stddev(...)
等等。built-in。
最后,请查看Rails指南中的query section和ARel,了解有关构建查询的更多信息。例如,您可以通过first
或limit
对ActiveRecord关系进行限制,在ARel中,take
允许您限制。子查询也是可能的,如this question的答案所示,分组依据等等。如果您与其他人共享此项目,请尝试限制您正在使用的非可移植SQL的数量,除非您计划自己添加对其他数据库的支持并维护它。