好的,所以我已经坚持了2天!我从语义的角度来解决它,但查询可能需要10分钟才能执行。我选择的数据库是SQLite(由于我不想在此详细说明),但我尝试在SQL Server 2012上运行相同的东西,但它在性能方面没有太大差别。
所以,问题是我有2个表
prices
(product_id INT,for_date DATE,value INT)events
(START_on DATE,ends_on DATE NULLABLE)我在价格表中有大约500K行,在事件表中有大约100行。
现在我需要编写一个查询来执行以下操作。
伪代码是:
我在SQL Server 2012中编写的查询是
SELECT
sp.for_date, sp.value
FROM
prices sp
INNER JOIN
events ev ON (((ev.ends_on IS NOT NULL AND
(sp.for_date = (SELECT for_date
FROM prices
WHERE for_date <= ev.ends_on
AND for_date > ev.starts_on
ORDER BY for_date DESC
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY))))
OR
((ev.ends_on is null
and
(sp.for_date = (SELECT for_date
FROM prices
WHERE
for_date <= ev.starts_on_j
AND for_date > dateadd(day, -14, ev.starts_on)
order by for_date desc
offset 0 rows
fetch next 1 row only))))
);
顺便说一下,我还尝试使用部分数据创建临时表,并对它们执行相同的操作。它只是卡住了。
奇怪的是,如果我单独运行2个“OR”条件,响应时间就完美了!
更新
示例数据集和预期结果
价格条目
Product ID, ForDt, Value
1, 25-01-2010, 123
1, 26-01-2010, 112
1, 29-01-2010, 334
1, 02-02-2010, 512
1, 03-02-2010, 765
1, 04-02-2010, 632
1, 05-02-2010, 311
1, 06-02-2010, 555
2, 03-02-2010, 854
2, 04-02-2010, 625
2, 05-02-2010, 919
3, 20-01-2010, 777
3, 06-02-2010, 877
3, 10-03-2010, 444
3, 11-03-2010, 888
活动参赛作品(为了使其更易理解,我也添加了一个活动ID)
Event ID, StartsOn, EndsOn
22, 27-01-2010, NULL
33, 02-02-2010, 06-02-2010
44, 01-03-2010, 13-03-2010
预期结果集
Event ID, Product ID, ForDt, Value
22, 1, 26-01-2010, 112
33, 1, 06-02-2010, 311
44, 1, 06-02-2010, 311
33, 2, 05-02-2010, 919
44, 2, 05-02-2010, 919
22, 3, 20-01-2010, 777
33, 3, 06-02-2010, 877
44, 3, 11-03-2010, 888
答案 0 :(得分:1)
好的,既然您已经将预期结果显示为事件列表和相关产品,那么这个问题就有意义了。您的查询仅选择日期和值。
您正在寻找每个活动的最佳产品价格记录。这可以通过分析函数轻松完成,但SQLite不支持它们。所以我们必须写一个更复杂的查询。
让我们首先看一下ends_on
null的事件。以下是如何找到最佳产品价格(即starts_on
之前的最后一次):
select e.event_id, p.product_id, max(for_date) as best_for_date
from events e
join prices p on p.for_date < e.starts_on
where e.ends_on is null
group by e.event_id, p.product_id;
我们扩展此查询以查找具有ends_on
的事件的最佳产品价格,然后再次访问products表格,以便我们获得包含值的完整记录:
select ep.event_id, p.product_id, p.for_date, p.value
from
(
select e.event_id, p.product_id, max(for_date) as best_for_date
from events e
join prices p on (e.ends_on is null and p.for_date < e.starts_on)
or (e.ends_on is not null and p.for_date between e.starts_on and e.ends_on)
group by e.event_id, p.product_id
) ep
join prices p on p.product_id = ep.product_id and p.for_date = ep.best_for_date;
(顺便说一句:你在这里描述了一个非常特殊的案例。到目前为止我看到的数据库会将ends_on
null
视为无限制或“仍然有效”。因此要检索的价格对于这样的事件,不会是 starts_on
之前的最后一个,而是 starts_on
之后或之后的最新。)