Если мы на мгновение проигнорируем столбец balance
и предположим, что столбец даты имеет тип данных DATE
, то получение показанного результата может быть достигнуто с помощью чего-то подобного:
SELECT t.date
, t.debit
, t.credit
FROM ( SELECT i.i_date AS date
, i.i_total AS debit
, 0 AS credit
, 'i' AS i_or_r
, i.i_id AS id
FROM invoice i
UNION ALL
SELECT r.r_date AS date
, 0 AS debit
, r.r_total AS credit
, 'r' AS i_or_r
, r.r_id AS id
FROM receiving r
) t
ORDER
BY t.date
, t.i_or_r
, t.id
Чтобы получить баланс, мы могли бы выполнить эту обработку на стороне клиента, так как строки извлекаются.
ПРИМЕЧАНИЕ: MySQL 8.0 представляет оконные функции, которые были доступны в других СУБД, таких как SQL Server и Oracle (называет их «Аналитические функции»).
Без оконных функций выполнение этого в SQL будет уродливым.
Мы могли бы использовать неподдерживаемое использование пользовательских переменных. Используя этот подход, мы в основном эмулировали бы обработку, которую мы выполняли бы на стороне клиента, извлекая результаты из этого запроса (обрабатывая каждую строку по порядку), чтобы сложить / вычесть из «текущего баланса» в определяемой пользователем переменной.
«Уродливая» часть этого - то, что это полагается на поведение, которое не гарантировано. Справочное руководство по MySQL содержит предупреждение об этом.)
Или, чтобы получить результат с использованием чистого SQL, мы могли бы использовать несколько сложных, выглядящих коррелированных подзапросов, чтобы суммировать суммы дебетов и кредитов до текущей строки, и делать это для каждой строки.
Похоже, что мы применяем дебеты и кредиты к балансу в том же порядке, что и банк, применяя все дебеты и кредиты в порядке дат. И в каждую дату мы сначала применяем дебет, а затем кредиты.
Из данных примера и ожидаемого результата неясно, применяются ли дебеты, упорядоченные по сумме в порядке возрастания или по идентификатору в порядке возрастания.
Используя данные выборки, мы получаем одинаковый результат баланса в любом случае. Предполагая, что i_id
уникален в счете, а cr_id
уникален в получении, мы можем получить баланс, применяя кредиты и дебеты, используя порядок id
в качестве дискриминатора, когда мы находимся на текущую дату.
(Если нам потребуется применить кредиты на одну и ту же дату в порядке возрастания суммы, подзапросы будут немного сложнее, чтобы учесть возможность того, что два кредита на одну и ту же дату могут быть на одну и ту же сумму.)
SELECT t.date
, t.debit
, t.credit
, ( SELECT SUM(bi.i_total)
FROM invoice bi
WHERE bi.i_date <= t.date
AND ( bi.i_date < t.date
OR ( t.i_or_r = 'i' AND bi.i_id <= t.id )
)
)
- ( SELECT SUM(br.cr_amount)
FROM receiving br
WHERE br.cr_date <= t.date
AND ( br.cr_date < t.date
OR ( t.i_or_r = 'r' AND br.cr_id <= t.id )
OR t.i_or_r = 'i'
)
) AS balance
FROM ( SELECT i.i_date AS date
, i.i_total AS debit
, 0 AS credit
, 'i' AS i_or_r
, i.i_id AS id
FROM invoice i
UNION ALL
SELECT r.cr_date AS date
, 0 AS debit
, r.cr_amount AS credit
, 'r' AS i_or_r
, r.cr_id AS id
FROM receiving r
) t
ORDER
BY t.date
, t.i_or_r
, t.id