MySQL查询难题-查找最近的日期

MySQL查询难题-查找最近的日期,mysql,join,max,datediff,min,Mysql,Join,Max,Datediff,Min,我已经看遍了所有的地方,还没有找到一个聪明的方法来处理这个问题,尽管我确信这是可能的: 一个历史数据表包含季度信息: CREATE TABLE Quarterly ( unique_ID INT UNSIGNED NOT NULL, date_posted DATE NOT NULL, datasource TINYINT UNSIGNED NOT NULL, data FLOAT NOT NULL, PRIMARY KEY (unique_ID)); CREATE TABLE Daily (

我已经看遍了所有的地方,还没有找到一个聪明的方法来处理这个问题,尽管我确信这是可能的:

一个历史数据表包含季度信息:

CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
PRIMARY KEY (unique_ID));
CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
qtr_ID INT UNSIGNED,
PRIMARY KEY (unique_ID));
另一个历史数据表(非常大)包含每日信息:

CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
PRIMARY KEY (unique_ID));
CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
qtr_ID INT UNSIGNED,
PRIMARY KEY (unique_ID));
qtr_ID字段不是填充数据库的每日数据提要的一部分-相反,我需要使用Quarterly.unique_ID行ID追溯填充daily表中的qtr_ID字段,使用为该数据源发布的daily.date_上的最新季度数据

例如,如果季度数据为

101 2009-03-31 14.5
102 2009-06-30 14.4
103 2009-03-3127.6
104 2009-06-30 27.7
105 2009-09-30 14.7

每天的数据是

10012009-07-1413.5??
1002 2009-07-15 13.4&&
1003 2009-07-1412.3

那么我们想要的是??qtr_ID字段将被指定为“102”,作为该数据源在该日期的最新季度,&&也将是“102”,并且^^将是“104”

挑战包括两个表(特别是每日表)实际上都非常大,它们无法进行规范化以消除重复日期或以其他方式进行优化,并且对于某些每日分录,没有之前的季度分录


我尝试过各种连接,使用datediff(其中的挑战是找到datediff的最小值大于零),以及其他尝试,但没有任何效果-通常我的语法在某个地方出现了问题。欢迎任何想法-我将执行任何基本想法或概念,并进行报告。

只需使用以下内容对季度id进行子查询:

(
 SELECT unique_ID 
 FROM Quarterly 
 WHERE 
     datasource = ? 
     AND date_posted >= ? 
 ORDER BY
     unique_ID ASC
 LIMIT 1
)
当然,这可能不会为您提供最佳性能,而且它假设日期按季度顺序添加(否则
按日期排序发布
)。然而,它应该能解决你的问题


您可以在
INSERT
UPDATE
语句上使用此子查询作为
qtr\u ID
字段的值,用于
Daily
表。

以下内容似乎完全按照预期工作,但肯定很糟糕(对同一日期调用了三次diff!!),也许通过查看一个正在运行的查询,有人可以进一步减少或改进它:

UPDATE Daily SET qtr_ID = (select unique_ID from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) = 
(SELECT MIN(DATEDIFF(Daily.date_posted, Quarterly.date_posted)) from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) > 0));

在对这个查询做了更多的工作之后,我最终得到了比最初的概念更大的性能改进。最重要的改进是在Daily和Quarterly表中创建索引——在Daily中,我使用BTREE在(datasource,date_posted)和(date_posted,datasource)上创建索引,在(datasource)上使用HASH创建索引,在Quarterly中我也做了同样的事情。这太过分了,但它确保了我有一个查询引擎可以使用的选项。这将查询时间减少到原来的1%以下。(!!)

然后,我了解到,鉴于我的特殊情况,我可以使用MAX()而不是orderby和LIMIT,因此我使用对MAX()的调用来获得适当的唯一ID。这将查询时间减少了约20%

最后,我了解到,使用InnoDB存储引擎,我可以用任何一个查询对正在更新的每日表的块进行分段,这使我可以用一点润滑脂和脚本对查询进行多线程处理。并行处理运行良好,每个线程都线性地减少了查询时间

因此,与我的第一次尝试相比,基本查询的性能实际上提高了1000倍:

UPDATE Daily
SET qtr_ID =
(
  SELECT MAX(unique_ID)
  FROM Quarterly
  WHERE Daily.datasource = Quarterly.datasource AND
        Daily.date_posted > Quarterly.dateposted
)
WHERE unique_ID > ScriptVarLowerBound AND
      unique_ID <= ScriptVarHigherBound
;
每日更新
设置qtr_ID=
(
选择最大值(唯一\u ID)
每季度
其中Daily.datasource=Quarterly.datasource和
Daily.date_posted>Quarterly.date posted
)
其中unique_ID>ScriptVarLowerBound和

unique_ID不幸的是,这并不完全起作用——它确实提取了正确的数据源,但它是根据最早的季度数据(然后提供第一个条目)之后经过的时间进行排序的,而不是最近的数据。因此,在上面的示例中,它为datasource='1'中的所有数据返回'101',为datasource='2'中的所有数据返回'103'。下面是我运行的:更新每日设置qtr_ID=(从Quarterly中选择unique_ID,其中Daily.datasource=Quarterly.datasource和Daily.date_posted>=Quarterly.date_posted ORDER BY date_posted BY date_posted ASC LIMIT 1),这个建议比我下面的成功查询要快得多。速度上的巨大差异使我一直在处理上面的建议,这导致我发现这只是一个需要做的小更改(按日期排序,按另一个方向发布),因此这是有效的代码,而且速度很快:更新每日设置qtr\U ID=(从季度中选择唯一的\u ID,其中Daily.datasource=Quarterly.datasource和Daily.date\u posted>=Quarterly.date\u posted ORDER BY date\u posted DESC LIMIT 1);感谢KenaniahHank,它更快的原因可能与unique_ID是一个索引字段这一事实有关。这是假设date_posted不是。有关比此更快的解决方案,请参阅上面的响应。