我期待构建一个SQL查询,它能够按月汇总分期值。通常这不会太难,因为你只需要分期付款和group by
月份。然而,问题并不那么容易,在帖子的其他部分,我将说明原因并征求人们能够提供的任何帮助。
首先,重要的是要注意installments
列。如果installments
为1,则表示在购买时支付总价值。如果installments
大于1,这意味着总价值在当月和下个月支付。例如,如果我们看到transaction_id
9和10,这是100美元的交易,有2期分期付款,这意味着2月份将支付50美元,3月份将支付50美元。
考虑一下,我们希望看到credit_card_id = 11111111
的每月账单。如果我们查看installments
列,我们可以看到正确的输出应该如下:
同样,为了清楚起见,3月份的75.3是因为我们在1月份进行了3次分期交易,这意味着客户将在1月,2月和3月收取75.3的费用。问题是我不知道如何根据给定的数据创建March的类别。
首先,我在SQL中重新创建了表,并且可以通过以下SQLite查询轻松地按月获取卡的所有事务
select strftime('%m', transaction_date) as Month, total_value, installment_value, installments
from transactions
WHERE credit_card_id = '11111111';
但是,如何将3个分期间分为01,02和03并不明显,所以我创建了一个新的表格,其中包含txn
列,这个列可以为唯一的事务提供一个id,可以被认为是1组。
CREATE TABLE transactions (
transaction_id int primary key,
credit_card_id int,
transaction_date timestamp,
merchant_name varchar(256),
total_value decimal(19,4),
installment_value decimal(19,4),
installments int,
txn int
);
insert into transactions values(1,11111111,'2018-01-10T00:00:00','Colorful Soaps', 19.99, 19.99, 1, 1);
insert into transactions values(2,22222222,'2018-01-11T00:01:00','Cantina da Mamma',43.5,43.5,1,2);
insert into transactions values(3,33333333,'2018-01-12T01:02:00','Boulevard Hotel',129,129,1,3);
insert into transactions values(4,11111111,'2018-01-15T11:11:11','Micas Bar',225.9,75.3,3,4);
insert into transactions values(5,11111111,'2018-01-15T11:11:11','Micas Bar',225.9,75.3,3,4);
insert into transactions values(6,11111111,'2018-01-15T11:11:11','Micas Bar',225.9,75.3,3,4);
insert into transactions values(7,22222222,'2018-01-18T22:10:01','IPear Store',9999.99,9999.99,1,5);
insert into transactions values(8,11111111,'2018-02-20T21:08:32','Forrest Paintball',1337,1337,1,6);
insert into transactions values(9,44444444,'2018-02-22T00:05:30','Unicorn Costumes',100,50,2,7);
insert into transactions values(10,44444444,'2018-02-22T00:05:30','Unicorn Costumes',100,50,2,7);
我的问题是
txn
专栏才能获得此信息?谢谢您的帮助。
假设您运行SQLite 3.25+版本,请考虑使用CTE and window function,它通过相同的credit_card_id和transaction_date创建运行计数,并使用此值将所需的月份添加到事务日期。从那里,根据新的计算日期,install_date聚合。
WITH cte AS
(SELECT *,
DATE(transaction_date,
'+' || (ROW_NUMBER()
OVER(PARTITION BY transaction_date, credit_card_id
ORDER BY transaction_date) - 1)
|| ' month'
) AS install_date
FROM transactions)
SELECT credit_card_id,
STRFTIME('%Y', install_date) AS install_year,
STRFTIME('%m', install_date) AS install_month,
SUM(installment_value) AS sum_installment_value
FROM cte
GROUP BY credit_card_id,
STRFTIME('%Y', install_date),
STRFTIME('%m', install_date)
ORDER BY credit_card_id,
STRFTIME('%Y', install_date),
STRFTIME('%m', install_date);
Rextester Demo使用PostgreSQL,因为AFAIK没有在线小提琴(SQLFiddle,SQLiteonline,DBFiddle等)支持带窗口函数的SQLite
SQLite有qazxsw poi(点击这里qazxsw poi)。
ROW_NUMBER()
分期付款超过两年时会出现问题。你将不得不工作那部分。我会在函数中编写这个代码(如果......),它会使整个查询更清晰。
这是一个不需要行编号的解决方案/将在更老的SQLite(任何支持date()的版本中工作)。它只依赖于日历表的连接(可以使用各种技术生成,但在链接的示例中,我通过创建表并直接插入查询所需的数据来生成N行,每个月的第1天都有一行。它使用笛卡尔连接条件,例如每次付款有3行,分三期:
SQLlite
你可以在 SELECT
installment_month
,credit_card_id
,SUM(installment_value)
FROM (
SELECT
CASE WHEN strftime('%m',transaction_date) + ROW_NUMBER () OVER(PARTITION BY credit_card_id, transaction_date ORDER BY transaction_date) - 1 > 12
THEN strftime('%Y',transaction_date)*100+strftime('%m',transaction_date) + ROW_NUMBER () OVER(PARTITION BY credit_card_id, transaction_date ORDER BY transaction_date) - 1 + 88
ELSE strftime('%Y',transaction_date)*100+strftime('%m',transaction_date) + ROW_NUMBER () OVER(PARTITION BY credit_card_id, transaction_date ORDER BY transaction_date) - 1
END as installment_month
,*
from transactions
) AS a
GROUP by installment_month, credit_card_id
看到设置
顺便说一下,你的问题或你的示例数据中有些东西搞砸了。
信用卡ID 11111111的每月付款是:
select
t.credit_card_id,
date(cal.d, '-1 month') as month_of_installment,
sum(t.installment_value)
from
cal inner join transactions t on
t.transaction_date between date(cal.d, '-'||installments||' months') and cal.d
group by
t.credit_card_id,
date(cal.d, '-1 month')
您的示例数据同时向Micas Bar支付了3笔款项。我们知道这些是不同的,因为它们具有不同的事务ID,尽管其他数据相同。问题断言,1月是75.3 + 75.3 + 75.3 + 19.99,而不仅仅是19.99 + 75.3。
要查看查询的更多工作方式,请运行非分组表单:
https://www.db-fiddle.com/f/ogj2hK3cMwqp46MY6uVwX8/0
我见过的大多数DBA主张在数据库中使用数字/日期表来生成诸如此类的查询 - 这是生成行序列的快速方法,并且在有例如数据的情况下为您提供一行连接。一个月没有交易(您可以将交易表连接到日历表并获得单行,总和为0,几个月没有交易)。在接下来的100年中产生一堆几个月/几天的行是一个微不足道的一次性操作