Как сделать недетерминированный запрос детерминированным? - PullRequest
0 голосов
/ 22 октября 2019

У меня есть следующая схема базы данных Sybase (сводится к таблицам вопросов):

         ___________         ___________         ________
        | MyEvent   |       | EventKind |       | Record |
        |———————————|       |———————————|       |————————|
        | ID        |    -->| ID        |    -->| ID     |
        | Date      |    |  | Label     |    |  | No     |
        | Amount    |    |  |___________|    |  | Date   |
        | kind_ID   |-FK-^                   |  |________|
        | record_ID |--------FK--------------^
        |___________|               

Меня попросили запросить определенный период для Record s, имеющих MyEvent s с указаннымLabel s (E2, I5) и суммируйте Amount s других MyEvent s, помеченных K0, K1 или K2, если они есть, в противном случае этот столбец таблицы результатовдолжен показать 0. Таблица результатов должна выглядеть следующим образом:

Наиболее важные и сложные требования:

  • выбранные записи, которые содержат хотя бы одно событие, помеченное как E2 или I5, могут содержатьоба
  • суммируют суммы событий, помеченных K0, K1 и K2, если они есть в записи, в противном случае возвращают 0
 _______________________________________________________________________________
| Record.No | Record.Date | MyEvent.Date | MyEvent.Date | SUM of MyEvent.Amount |
|           |             |      E2      |      I5      |     K0, K1 and K2     |
 ———————————————————————————————————————————————————————————————————————————————
| 12345     | 2019-10-01  |     NULL     |  2019-10-10  |        52,20          |
| 23456     | 2018-02-15  |  2018-02-30  |  2018-05-10  |        34,80          | 
| 34567     | 2017-06-26  |     NULL     |  2017-07-04  |            0          | 
| 45678     | 2015-03-17  |  2017-07-04  |     NULL     |       129,10          | 
 ———————————————————————————————————————————————————————————————————————————————

В настоящее время я не могучтобы получить какой-либо результат, хотя я уверен, что есть тонны Record с одним из MyEvent s E2 и I5 (или обоими), а также многие из них с пометкой MyEvent sK0, K1 или K2.

Мой текущий подход заключается в следующем, который использует CASE WHEN ... THEN ... ELSE ... END, но в настоящее время приходится повторно использовать подзапросы (в любом случае, уродливо, но, очевидно, неправильно):

SELECT DISTINCT
    r.No AS "Record.No",
    ----------------------------------------------------------------
    r.Date AS "Record.Date",
    ----------------------------------------------------------------
    CASE
    WHEN NOT EXISTS (
        SELECT FIRST
            MyEvent.Date
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label = 'E2'
    ) THEN NULL
    ELSE (
        SELECT FIRST
            MyEvent.Date
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label = 'E2'
    ) END AS "MyEvent.Date E2",
    ----------------------------------------------------------------
    CASE
    WHEN NOT EXISTS (
        SELECT FIRST
            MyEvent.Date
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label = 'I5'
    ) THEN NULL
    ELSE (
        SELECT FIRST
            MyEvent.Date
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label = 'I5'
    ) END AS "MyEvent.Date I5",
    ----------------------------------------------------------------
    CASE
    WHEN (
        SELECT
            SUM(MyEvent.Amount)
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label IN ('K0', 'K1', 'K2')
    ) IS NULL THEN 0
    ELSE (
        SELECT
            SUM(MyEvent.Amount)
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            EventKind.Label IN ('K0', 'K1', 'K2')
    ) END AS "Sum of MyEvent.Amount K0, K1 and K2"
    ----------------------------------------------------------------
FROM
    Record r
    INNER JOIN MyEvent e ON e.record_ID = r.ID
    INNER JOIN EventKind k ON k.ID = e.kind_ID
WHERE
    a.clientNo IN (515, 520, 521, 522, 535, 632, 832, 853, 889, 890, 892, 893, 894, 895, 934)
    AND
    a.Date BETWEEN '2008-01-01' AND '2018-12-31'
    AND
    EXISTS (
        SELECT FIRST
            MyEvent.Date
        FROM
            MyEvent
            INNER JOIN EventKind ON EventKind.ID = MyEvent.kind_ID
        WHERE
            MyEvent.record_ID = r.ID
            AND
            (
                EventKind.Label = 'I5'
                OR
                EventKind.Label = 'E2'
            )
    )
ORDER BY
    r.No ASC

При использовании этого запроса первое, что я получаю, это предупреждение, которое уже является подсказкой, указывающей на что-то не так с запросом :

Sybase warning about non deterministic result

Второе, что я получаю, это, к сожалению, 0 rows returned, который определеннона самом деле это не желаемый вывод ;-)

Ожидаемый вывод - 58200 строк с правильными датами и суммами событий.

РЕДАКТИРОВАТЬ

После исправления нескольких ошибок в запросе я теперь получаю правильное количество результатов, и все случайные выборки, которые я проверил, верны, , но предупреждение о недетерминированности результата все равно показывает .

Как мне от этого избавиться? Это заставляет меня чувствовать себя плохо, потому что это подразумевает, возможно, разные результаты для разных занятий, не так ли? До сих пор я выполнял его 5 раз, и результаты были равны…

Если у кого-нибудь есть предложения по сокращению кода SQL, я бы с удовольствием их прочитал.

...