具有多个AND条件的Oracle SELECT,用于多列(INTERSECT替代)

时间:2016-09-01 09:14:19

标签: sql oracle intersect relational-division

如何解决以下问题:

想象一下,我们有一个大型建筑物,有大约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分钟。

是否有更好(更快)的方法来获得结果?

3 个答案:

答案 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)

或许这会比使用ORIN子句提供更好的计划。