在不借助 PL/SQL 的情况下从第二个表中查找相关值
Posted
技术标签:
【中文标题】在不借助 PL/SQL 的情况下从第二个表中查找相关值【英文标题】:Finding correlated values from second table without resorting to PL/SQL 【发布时间】:2009-04-07 18:38:35 【问题描述】:我的数据库中有以下两个表:
a) 包含在特定日期获取的值的表格(您可以将这些视为温度读数):
读数之间的间隔可能不同,但 (sensor_id
, acquired
) 的组合是唯一的。
b) 包含时间段和描述的第二个表(您可以将这些视为,例如,有人打开散热器的时间段):
同样,时间段的长度可能不同,但任何给定传感器都不会有重叠的时间段。
对于任何传感器和任何日期范围,我都希望得到类似这样的结果:
或文本来自:给定sensor_id
和range_start
和range_end
的日期范围,
找到与日期范围重叠的所有时间段(即start_date < range_end
和end_date > range_start
),对于这些行中的每一行,从值表中找到时间段start_date
和end_date
的对应值(用acquired > start_date
和acquired > end_date
找到第一行)。
如果不是 start_value
和 end_value
列,这将是一个教科书般的简单示例,说明如何连接两个表。
我能否以某种方式在一条 SQL 语句中获得所需的输出,而无需编写 PL/SQL 函数来查找这些值?
除非我忽略了一些明显的东西,否则这不能用简单的子选择来完成。
数据库是 Oracle 11g,因此任何特定于 Oracle 的特性都是可以接受的。
编辑:是的,循环是可能的,但我想知道这是否可以通过单个 SQL 选择来完成。
【问题讨论】:
【参考方案1】:你可以试试这个。不过请注意最后的警告。
SELECT
RNG.sensor_id,
RNG.start_date,
RDG1.value AS v1,
RNG.end_date,
RDG2.value AS v2,
RNG.description
FROM
Ranges RNG
INNER JOIN Readings RDG1 ON
RDG1.sensor_id = RNG.sensor_id AND
RDG1.acquired => RNG.start_date
LEFT OUTER JOIN Readings RDG1_NE ON
RDG1_NE.sensor_id = RDG1.sensor_id AND
RDG1_NE.acquired >= RNG.start_date AND
RDG1_NE.acquired < RDG1.acquired
INNER JOIN Readings RDG2 ON
RDG2.sensor_id = RNG.sensor_id AND
RDG2.acquired => RNG.end_date
LEFT OUTER JOIN Readings RDG1_NE ON
RDG2_NE.sensor_id = RDG2.sensor_id AND
RDG2_NE.acquired >= RNG.end_date AND
RDG2_NE.acquired < RDG2.acquired
WHERE
RDG1_NE.sensor_id IS NULL AND
RDG2_NE.sensor_id IS NULL
这使用范围开始日期之后的第一个读数和结束日期之后的第一个读数(我个人认为使用开始和结束之前的最后一个日期会更有意义或最接近的值,但我不知道你的应用程序)。如果没有这样的阅读,那么您将一无所获。您可以将 INNER JOIN 更改为 OUTER,并根据您自己的业务规则添加额外的逻辑来处理这些情况。
【讨论】:
OUTER JOIN 的绝妙技巧,现在我为什么没有想到呢? :) 感谢您证明这是可以做到的,而且,确实,是我愚蠢。【参考方案2】:看起来很简单。
查找每个范围的传感器值。找到一行 - 我将调用该行的获取只是 X - 其中 X > start_date
并且不存在任何其他带有 acquired > start_date
和 acquired < X
的行。对结束日期执行相同操作。
仅选择满足查询条件的范围 - start_date 早于和 end_date 晚于查询提供的日期。
在 SQL 中就是这样。
SELECT R1.*, SV1.aquired, SV2.aquired
FROM ranges R1
INNER JOIN sensor_values SV1 ON SV1.sensor_id = R1.sensor_id
INNER JOIN sensor_values SV2 ON SV2.sensor_id = R1.sensor_id
WHERE SV1.aquired > R1.start_date
AND NOT EXISTS (
SELECT *
FROM sensor_values SV3
WHERE SV3.aquired > R1.start_date
AND SV3.aquired < SV1.aquired)
AND SV2.aquired > R1.end_date
AND NOT EXISTS (
SELECT *
FROM sensor_values SV4
WHERE SV4.aquired > R1.end_date
AND SV4.aquired < SV2.aquired)
AND R1.start_date < @range_start
AND R1.end_date > @range_end
【讨论】:
我的错误,我没有澄清我试图在一个 SQL 查询中找到一种方法来执行此操作。否则,是的,你的想法是非常有效的,也是实现这一点的最直接的方法。 我了解到您只需要一个查询。您可以将所有内容放在一个巨大的查询中。不好,但可能。以上是关于在不借助 PL/SQL 的情况下从第二个表中查找相关值的主要内容,如果未能解决你的问题,请参考以下文章