如何解决以下问题:
想象一下,我们有一个大型建筑物,有大约100个温度读数器,每个温度读数器每分钟收集一次温度。
我有一个相当大的表(~100m)行,其中包含以下列:
表TempEvents:
Timestamp - one entry per minute
Reader ID - about 100 separate readers
Temperature - Integer (-40 -> +40)
时间戳和读卡器ID是表的主键+辅助键。我想执行一个查询,查找所有时间戳,其中reader_01 = 10度,读取器_02 = 15度,读取器_03 = 20度。
换句话说就是这样:
SELECT Timestamp FROM TempEvents
WHERE (readerID=01 AND temperature=10)
AND (readerID=02 AND temperature=15)
AND (readerID=03 AND temperature=20)
==>导致时间戳列表:
Timestamp::
2016-01-01 05:45:00
2016-02-01 07:23:00
2016-03-01 11:56:00
2016-04-01 23:21:00
由于单行不包含所有条件,因此上述查询不返回任何内容。在条件之间使用OR也不会产生期望的结果,因为所有读者都应该匹配条件。
使用INTERSECT,我可以得到结果:
SELECT * FROM
(SELECT Timestamp FROM TempEvents WHERE readerID=01 AND temperature=10
INTERSECT SELECT Timestamp FROM TempEvents WHERE readerID=02 AND temperature=15
INTERSECT SELECT Timestamp FROM TempEvents WHERE readerID=03 AND temperature=20
)
GROUP BY Timestamp ORDER BY Timestamp ASC;
上述查询成本极高,执行时间约为5分钟。
是否有更好(更快)的方法来获得结果?
答案 0 :(得分:1)
我刚刚在Oracle DB中尝试了这个,它似乎有效:
SELECT Timestamp FROM TempEvents
WHERE (readerID=01 AND temperature=10)
OR (readerID=02 AND temperature=15)
OR (readerID=03 AND temperature=20)
确保仅更改括号外的AND
答案 1 :(得分:0)
如果您要查询的阅读器数量不是太大,您可以尝试使用select distinct Timestamp
from TempEvents t1
join TempEvents t2 using(Timestamp)
join TempEvents t3 using(Timestamp)
where t1.readerID=01 and t1.temperature = 10
and t2.readerID=02 and t2.temperature = 15
and t3.readerID=03 and t3.temperature = 20
- 查询
INTERSECT
但说实话,我怀疑它的效果会比Text_IO.FREMOVE
- 查询更好。
答案 2 :(得分:0)
试试这个:
with Q(readerID,temperature) as(
select 01, 10 from dual
union all
select 02,15 from dual
union all
select 03,20 from dual
)
select Timestamp FROM TempEvents T, Q
where T.readerID=Q.readerID and T.temperature=Q.temperature
group by Timestamp
having count(1)=(select count(1) from Q)
或许这会比使用OR
或IN
子句提供更好的计划。