Найти все значения, которые не вписываются ни в один из нескольких определенных диапазонов - PullRequest
0 голосов
/ 31 августа 2018

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

Допустимые диапазоны дат

+----------+------------+------------+
| SensorID | StartDate  | EndDate    |
+----------+------------+------------+
|        1 | 2018-01-01 | 2018-01-08 |
|        1 | 2018-01-10 | 2018-01-13 |
|        1 | 2018-01-14 | 2018-01-17 |
|        1 | 2018-01-21 | 2018-01-31 |
+----------+------------+------------+

Список данных дат

+----------+------------+-------+
| SensorID | Read_Date  | Value |
+----------+------------+-------+
|        1 | 2018-01-01 |   100 |
|        1 | 2018-01-02 |   200 |
|        1 | 2018-01-03 |   300 |
|        1 | 2018-01-09 |   400 |
|        1 | 2018-01-10 |   400 |
|        1 | 2018-01-14 |   250 |
|        1 | 2018-01-18 |   300 |
|        1 | 2018-01-18 |   400 |
|        1 | 2018-01-19 |   350 |
|        1 | 2018-01-24 |   400 |
+----------+------------+-------+

Конечным результатом должна быть полная запись из второй таблицы, т. Е.

+----------+------------+-------+
| SensorID | Read_Date  | Value |
+----------+------------+-------+
|        1 | 2018-01-09 |   400 |
|        1 | 2018-01-18 |   300 |
|        1 | 2018-01-18 |   400 |
|        1 | 2018-01-19 |   350 |
+----------+------------+-------+

Я думал о том, чтобы найти все записи, которые являются действительными записями, используя BETWEEN, а затем EXCEPT из записей из полного набора данных, но он слишком большой. Есть ли способ присоединиться, используя NOT BETWEEN?

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Подход, который вы выбираете, действителен, но его можно сделать более эффективным. Я обычно избегаю использования отдельного предложения в моих высказываниях, если это не является абсолютно необходимым. Они часто являются признаками того, что объединение написано неправильно и / или неоптимально.

Я рекомендую использовать левое анти-полусоединение для более эффективного возврата ваших данных. Следующая статья поможет немного подробнее объяснить, что я предлагаю вам сделать: https://sqlity.net/en/1360/a-join-a-day-the-left-anti-semi-join/

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

SELECT  *
FROM    #record_dates AS rd
WHERE   NOT EXISTS
    (
        SELECT  TOP (1)
                vd.SensorID
        FROM    #valid_dates AS vd
        WHERE   vd.SensorID = rd.SensorID
            AND rd.Read_Date BETWEEN vd.StartDate AND vd.EndDate
        ORDER BY vd.SensorID ASC
    )

Должен отметить, что я предполагаю, что SensorID проиндексирован. Я обнаружил, что добавление ORDER BY к кластерному индексу при выборе записи top (1) помогает с планом запроса, хотя при игнорировании этого фрагмента производительность может возрасти.

0 голосов
/ 31 августа 2018

Я считаю, что это так же просто, как:

SELECT *
FROM given_dates
WHERE NOT EXISTS (
    SELECT 1
    FROM valid_date_ranges
    WHERE given_dates.SensorID = valid_date_ranges.SensorID
    AND   given_dates.Read_Date BETWEEN StartDate AND EndDate
)

Также можно написать выше как LEFT JOIN ... WHERE keycol IS NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...