从第二个表中查找相关值而不依赖于PL / SQL

时间:2009-04-07 18:38:36

标签: sql oracle

我的数据库中有以下两个表:

a)包含在特定日期获得的值的表格(您可以将其视为温度读数):

 sensor_id |       acquired      | value
 ----------+---------------------+--------
 1         | 2009-04-01 10:00:00 | 20
 1         | 2009-04-01 10:01:00 | 21
 1         | 2009-04 01 10:02:00 | 20
 1         | 2009-04 01 10:09:00 | 20
 1         | 2009-04 01 10:11:00 | 25
 1         | 2009-04 01 10:15:00 | 30
 ...

读数之间的间隔可能不同,但(sensor_idacquired)的组合是唯一的。

b)包含时间段和描述的第二个表格(您可以将这些视为某人打开散热器的时段):

 sensor_id |      start_date     |       end_date      | description
 ----------+---------------------+---------------------+------------------
 1         | 2009-04-01 10:00:00 | 2009-04-01 10:02:00 | some description
 1         | 2009-04-01 10:10:00 | 2009-04-01 10:14:00 | something else

同样,周期的长度可能不同,但任何给定的传感器都不会有重叠的时间段。

我希望得到任何传感器和任何日期范围的结果:

sensor id |     start date      | v1 |       end date      | v2 | description
----------+---------------------+----+---------------------+----+------------------
1         | 2009-04-01 10:00:00 | 20 | 2009-04-01 10:02:00 | 20 | some description
1         | 2009-04-01 10:10:00 | 25 | 2009-04-01 10:14:00 | 30 | some description

或者来自以下文字:给定sensor_id且日期范围为range_startrange_end, 找到所有与日期范围重叠的时间段(即start_date < range_endend_date > range_start),并为每个行找到时间段{{1}的值表中的相应值}和start_date(找到end_dateacquired > start_date的第一行。

如果不是acquired > end_datestart_value列,这将是一个教科书如何连接两个表的简单示例。

我可以以某种方式在一个SQL语句中获取我需要的输出而无需编写PL / SQL函数来查找这些值吗?

除非我忽略了明显的明显事实,否则不能用简单的子选择来完成。

数据库是Oracle 11g,因此任何特定于Oracle的功能都是可以接受的。

编辑:是的,循环是可能的,但我想知道是否可以通过单个SQL选择来完成。

2 个答案:

答案 0 :(得分: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,并根据您自己的业务规则添加其他逻辑来处理这些情况。

答案 1 :(得分:0)

看起来很简单。

  1. 查找每个范围的传感器值。找到一行 - 我将调用此行的获取者X - X > start_date,而不存在acquired > start_dateacquired < X的任何其他行。对结束日期也这样做。

  2. 仅选择符合查询的范围 - 查询提供日期之前的start_date和end_date。

  3. 在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