【发布时间】:2020-03-02 06:09:01
【问题描述】:
在名为 reason 的表中查找一行时:
machine_id reason start_time
001234 moving 10:00:00
001234 parked 10:10:00
001234 moving 10:15:00
001234 NULL 10:20:00
001234 NULL 10:25:00
001234 dumping 10:30:00
009876 parked 10:00:00
009876 NULL 10:10:00
009876 NULL 10:15:00
009876 moving 10:20:00
009876 dumping 10:25:00
无论出于何种原因,我都需要获取不是 NULL 的最新值,因此 001234 NULL 值都将变为“移动”,而 009876 NULL 值将都变为“停放”。
我通常会通过交叉应用来解决这个问题:
SELECT
r1.machine_id
,ISNULL(r1.reason,r2.reason) AS reason
,r1.start_time
FROM #reason r1
CROSS APPLY(
SELECT TOP 1
r2.reason
FROM #reason r2
WHERE r2.machine_oid = r1.machine_oid
AND r2.start_time < r1.start_time
AND r2.reason IS NOT NULL
ORDER BY start_time DESC
) r2
但是我查询的这张表有几十万行(无法修改源数据库),查询的复杂度似乎接近n^2。
在 C++ 中,我会通过使用优先级队列并丢弃对象列表中的项目来检查不符合标准的项目,因此复杂性更接近 nlogn。
我尝试在此处理解有关使用表作为队列的帖子:http://rusanu.com/2010/03/26/using-tables-as-queues,但这超出了我的技能水平。
因为这是对我的数据集非常普遍的要求,我希望有一个可以应用的优雅解决方案?
【问题讨论】:
-
在发布此内容后,我有了一个想法,即通过加入日期 ID 并将比较表分解成更小的块,并且只回顾前一天。这提高了更接近 nlogn 的性能,但使用优先级队列仍然会好很多。
标签: sql sql-server tsql sql-server-2017