Как создать MySQL Query с накоплением на созданном поле? - PullRequest
0 голосов
/ 02 мая 2018

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

enter image description here

Как мне достичь желаемого баланса с помощью запроса или функции в MySQL?

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Попробуйте

SELECT *, SUM(Debit) OVER(ORDER BY dt,debit ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)-SUM(Credit) OVER(ORDER BY dt,debit ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) Balance
FROM (
SELECT ID,Dt,Amount AS Debit,0 AS Credit FROM Debit
UNION ALL
SELECT ID,Dt,0 AS Debit,Amount AS Credit FROM Credit
)X 
ORDER BY DT

DEMO

0 голосов
/ 02 мая 2018

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