我的数据库中有以下两个表:
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_id
,acquired
)的组合是唯一的。
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_start
和range_end
,
找到所有与日期范围重叠的时间段(即start_date < range_end
和end_date > range_start
),并为每个行找到时间段{{1}的值表中的相应值}和start_date
(找到end_date
和acquired > start_date
的第一行。
如果不是acquired > end_date
和start_value
列,这将是一个教科书如何连接两个表的简单示例。
我可以以某种方式在一个SQL语句中获取我需要的输出而无需编写PL / SQL函数来查找这些值吗?
除非我忽略了明显的明显事实,否则不能用简单的子选择来完成。
数据库是Oracle 11g,因此任何特定于Oracle的功能都是可以接受的。
编辑:是的,循环是可能的,但我想知道是否可以通过单个SQL选择来完成。
答案 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)
看起来很简单。
查找每个范围的传感器值。找到一行 - 我将调用此行的获取者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