Поиск коррелированных значений из второй таблицы без обращения к PL / SQL - PullRequest
1 голос
/ 07 апреля 2009

В моей базе данных есть следующие две таблицы:

a) Таблица, содержащая значения, полученные на определенную дату (вы можете думать о них, например, как о показаниях температуры): </p> <pre> 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 ... </pre> <p> Интервал между показаниями может отличаться, но комбинация (sensor_id, acquired) является уникальной.

b) Вторая таблица, содержащая периоды времени и описание (вы можете думать о них, например, как о периодах, когда кто-то включал радиатор): </p> <pre> 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 </pre> <p> Опять же, длина периода может отличаться, но для любого конкретного датчика никогда не будет перекрывающихся периодов времени.

Я хочу получить результат, который выглядит следующим образом для любого датчика и любого диапазона дат:

</p> <pre> 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 </pre> <p> Или в тексте из: дано 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.

Ответы [ 2 ]

1 голос
/ 07 апреля 2009

Вы можете попробовать. Обратите внимание на предостережения в конце.

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

При этом используется первое чтение после начальной даты диапазона и первое чтение после конечной даты (лично я думаю, что использование последней даты перед началом и концом будет более целесообразным или ближайшим значением, но я не знаю ваше приложение). Если такого чтения нет, вы вообще ничего не получите. Вы можете изменить ВНУТРЕННИЕ СОЕДИНЕНИЯ на ВНЕШНИЙ и добавить дополнительную логику для обработки этих ситуаций на основе ваших собственных бизнес-правил.

0 голосов
/ 07 апреля 2009

Это кажется довольно прямым.

  1. Найти значения датчика для каждого диапазона. Найдите строку - я назову приобретенную из этой строки просто X - где X > start_date и не существует ни одной другой строки с acquired > start_date и acquired < X. Сделайте то же самое для даты окончания.

  2. Выберите только диапазоны, которые соответствуют запросу - начальная_дата до и конечная_дата после дат, указанных в запросе.

В 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...