У меня есть одна таблица, как показано ниже, MySQL
customer_id,invoice_id,invoice_month,payment_month,invoice_amount,payment_amt,balance_amt
1,1,"DEC 23","JAN 24",400.00,400.00,0.00
1,2,"DEC 23","JAN 24",600.00,600.00,0.00
1,3,"JAN 24","JAN 24",200.00,50.00,150.00
2,4,"SEP 23","MAY 24",800.00,800.00,0.00
2,5,"OCT 23","MAY 24",750.00,750.00,0.00
3,6,"FEB 24","MAY 24",925.00,525.00,400.00
4,7,"NOV 22","JUN 23",325.00,325.00,0.00
4,8,"DEC 22","JUN 23",425.00,425.00,0.00
5,9,"JUN 24",NULL,500.00,NULL,500.00
Таблица платежей как
customer_id,payment_month,amount
1,JAN 24,500
1,FEB 24,550
2,MAR 24,450
2,APR 24,900
2,MAY 24,450
3,MAY 24,525
4,JUN 23,350
4,JUN 23,400
необходимо создать новые столбцы «Payment_final_month» на основе «Payment_month» из таблицы платежей. Для первой записи у меня есть сумма счета-фактуры, равная 400, что меньше суммы в таблице платежей. Первая запись, затем выберите 24 января. Для второй записи, поскольку у меня осталось 100 от первой записи, выберите то же самое 24 января. Для третьей записи я должен выбрать 24 февраля.
Окончательный результат что-то вроде
customer_id invoice_id invoice_month payment_month invoice_amount payment_amt balance_amt payment_final_month
1 1 DEC 23 JAN 24 400.00 400.00 0.00 JAN 24
1 2 DEC 23 JAN 24 600.00 600.00 0.00 JAN 24
1 3 JAN 24 FEB 24 200.00 50.00 150.00 FEB 24
2 4 SEP 23 MAR 24 800.00 800.00 0.00 MAR 24
2 5 OCT 23 APR 24 750.00 750.00 0.00 APR 24
3 6 FEB 24 MAY 24 925.00 525.00 400.00 MAY 24
4 7 NOV 22 JUN 23 325.00 325.00 0.00 JUN 23
4 8 DEC 22 JUN 23 425.00 425.00 0.00 JUN 23
5 9 JUN 24 NULL 500.00 NULL 500.00 NULL
Я попробовал подход ниже и не сработал
i.invoice_amount - COALESCE(LAG(i.payment_amt, 1) OVER (PARTITION BY i.customer_id ORDER BY i.invoice_id), 0) AS remaining_amount
@P.Salmon . Большое спасибо за ответ. Возможно, я не смогу вносить изменения в даты, поскольку у меня есть даты в том же формате: МОН ГГ. Есть ли какое-нибудь предложение, которое вы можете мне помочь?..
@ysth. Большое спасибо за комментарий. Есть ли какое-нибудь предложение, я могу попробовать, пожалуйста
@ysth 100 следует учитывать для следующей записи. Поскольку часть 1-й записи из 500 400 меньше 500, а осталось 100, и в качестве причины для 2-й записи также следует выбрать 24 января. Он должен идти в порядке возрастания и выбирать следующее по величине значение на основе разницы Счет с оплатой
У счета-фактуры 2 было 100 оплачено 24 января, а оставшиеся 500 оплачено 24 февраля. Почему платеж_final_month должен быть 24 января?
у вас действительно нет первичного ключа для таблицы платежей?
Это немного запутанно, потому что есть некоторые проблемы с дизайном, связанные с ключами, связями и (особенно) датами.
Чтобы решить эту проблему, вам следует преобразовать строки месяца в типы данных даты. Один из способов сделать это — использовать cte для преобразования типов данных даты и расчета текущих сумм (кумулятивов) для сумм счетов и платежей.
Итак, с вашим примером данных:
WITH -- S a m p l e D a t a :
invoices (customer_id, invoice_id, invoice_month, payment_month,
invoice_amount, payment_amt, balance_amt) AS
( Select 1, 1, 'DEC 23', 'JAN 24', 400.00, 400.00, 0.00 Union All
Select 1, 2, 'DEC 23', 'JAN 24', 600.00, 600.00, 0.00 Union All
Select 1, 3, 'JAN 24', 'JAN 24', 200.00, 50.00, 150.00 Union All
Select 2, 4, 'SEP 23', 'MAY 24', 800.00, 800.00, 0.00 Union All
Select 2, 5, 'OCT 23', 'MAY 24', 750.00, 750.00, 0.00 Union All
Select 3, 6, 'FEB 24', 'MAY 24', 925.00, 525.00, 400.00 Union All
Select 4, 7, 'NOV 22', 'JUN 23', 325.00, 325.00, 0.00 Union All
Select 4, 8, 'DEC 22', 'JUN 23', 425.00, 425.00, 0.00 Union All
Select 5, 9, 'JUN 24', NULL, 500.00, NULL, 500.00
),
payments (customer_id, payment_month, amount) AS
( Select 1, 'JAN 24', 500 Union All
Select 1, 'FEB 24', 550 Union All
Select 2, 'MAR 24', 450 Union All
Select 2, 'APR 24', 900 Union All
Select 2, 'MAY 24', 450 Union All
Select 3, 'MAY 24', 525 Union All
Select 4, 'JUN 23', 350 Union All
Select 4, 'JUN 23', 400
),
... сначала создайте cte, который будет использоваться для преобразования месяцев в даты...
-- months conversion cte
dates (mon, mm) AS
( Select 'JAN', '01' Union All
Select 'FEB', '02' Union All
Select 'MAR', '03' Union All
Select 'APR', '04' Union All
Select 'MAY', '05' Union All
Select 'JUN', '06' Union All
Select 'JUL', '07' Union All
Select 'AUG', '08' Union All
Select 'SEP', '09' Union All
Select 'OCT', '10' Union All
Select 'NOV', '11' Union All
Select 'DEC', '12'
),
... затем создайте еще два CTE для преобразования дат (используя указанный выше CTE) и для просчета сумм счетов и сумм платежей...
-- prepare payment data (cumulative sums and dates)
payments_cumul AS
( Select p.customer_id, p.payment_month, p.amount,
STR_TO_DATE( Concat('01', d.mm, SubStr(p.payment_month, 5, 2)), '%d%m%y' ) as pay_date,
Sum(p.amount) Over(Partition By p.customer_id
Order By STR_TO_DATE( Concat('01', d.mm, SubStr(p.payment_month, 5, 2)), '%d%m%y' )
Rows Between Unbounded Preceding And Current Row) as pay_amt_cumul
From payments p
Inner Join dates d ON( d.mon = SubStr(p.payment_month, 1, 3))
),
-- prepare invoice data (cumulative sums and dates)
grid as
( Select i.customer_id, i.invoice_id,
i.invoice_month, i.payment_month as inv_payment_month,
i.invoice_amount,
Sum(i.invoice_amount) Over( Partition By i.customer_id, i.payment_month
Order By STR_TO_DATE( Concat('01', d.mm, SubStr(i.payment_month, 5, 2)), '%d%m%y' )
Rows Between Unbounded Preceding And Current Row
) as inv_amt_cumul,
i.payment_amt, i.balance_amt,
STR_TO_DATE( Concat('01', d.mm, SubStr(i.payment_month, 5, 2)), '%d%m%y' ) as inv_pay_date
From invoices i
Left Join dates d ON( d.mon = SubStr(i.payment_month, 1, 3) )
)
... наконец, соедините все это вместе, агрегируйте и сгруппируйте по...
-- M a i n S Q L :
Select g.customer_id, g.invoice_id,
Max(g.invoice_month) as invoice_month,
g.inv_payment_month,
g.invoice_amount, g.payment_amt, g.balance_amt,
DATE_FORMAT(Case When g.inv_amt_cumul - Max(Coalesce(p.pay_amt_cumul, 0)) > 0
Then Coalesce(Max(p.pay_date), g.inv_pay_date)
Else g.inv_pay_date
End, '%M %y') as payment_final_month
From grid g
Left Join payments_cumul p ON( p.customer_id = g.customer_id And
g.inv_amt_cumul >= p.pay_amt_cumul
)
Group By g.customer_id, g.invoice_id, g.inv_payment_month, g.inv_pay_date,
g.invoice_amount, g.payment_amt, g.balance_amt
Order By g.customer_id, g.invoice_id
/* R e s u l t :
customer_id invoice_id invoice_month inv_payment_month invoice_amount payment_amt balance_amt payment_final_month
----------- ---------- -------------- ------------------ -------------- ----------- ----------- -------------------
1 1 DEC 23 JAN 24 400.00 400.00 0.00 January 24
1 2 DEC 23 JAN 24 600.00 600.00 0.00 January 24
1 3 JAN 24 JAN 24 200.00 50.00 150.00 February 24
2 4 SEP 23 MAY 24 800.00 800.00 0.00 March 24
2 5 OCT 23 MAY 24 750.00 750.00 0.00 April 24
3 6 FEB 24 MAY 24 925.00 525.00 400.00 May 24
4 7 NOV 22 JUN 23 325.00 325.00 0.00 June 23
4 8 DEC 22 JUN 23 425.00 425.00 0.00 June 23
5 9 JUN 24 null 500.00 null 500.00 null */
См. скрипку здесь.
ОБНОВЛЕНИЕ: (Код ошибки: 1270. Недопустимое сочетание параметров сортировки)
смешанная сортировка внутри функции Concat() вызывает ошибку. Первые две строки в concat — utf8, а третья — latin1. Используйте явное сопоставление либо для первых двух, либо для третьего и сделайте их одинаковыми (все 4 объединения в коде):
STR_TO_DATE( Concat('01', -- utf8
d.mm, -- utf8
SubStr(p.payment_month COLLATE utf8mb4_0900_ai_ci, 5, 2)),
'%d%m%y' )
ИЛИ
STR_TO_DATE( Concat('01' COLLATE latin1_swedish_ci,
d.mm COLLATE latin1_swedish_ci,
SubStr(p.payment_month, 5, 2)), -- latin1
'%d%m%y' )
@d r, спасибо большое. Я попробовал и получил ошибку с кодом ошибки: 1270. Недопустимое сочетание параметров сортировки (utf8mb4_0900_ai_ci,COERCIBLE), (utf8mb4_0900_ai_ci,COERCIBLE), (latin1_swedish_ci,IMPLICIT) для операции 'concat'
@Arya Только что опубликовала сообщение об этой ошибке.
Можете ли вы изменить дизайн, чтобы включить даты в качестве типа данных даты и сохранить фактические даты?