我正在寻求构建一个SQL查询,该查询能够按月汇总分期付款值。通常,这并不难,因为您只需将分期付款值和group by
月份相加即可。但是,问题并不是那么容易,在本文的其余部分中,我将说明原因并寻求人们能够提供的任何帮助。
首先,请务必注意installments
列。 installments
为1时,表示总值在购买时支付。 installments
大于1时,表示在当月及以后的月份中支付了总价。例如,如果我们看到transaction_id
9和10,则这是一笔100美元的交易,分两期付款,这意味着50美元将在2月支付,而50美元将在3月支付。
考虑我们要查看credit_card_id = 11111111
的每月帐单。如果我们查看installments
列,我们可以看到正确的输出应如下:
再次清楚地说,发生在3月的75.3是因为我们在1月进行了3笔分期付款交易,这意味着将在1月,2月和3月向客户收取75.3的费用。问题是我不知道如何根据给定的数据创建3月的类别。
首先,我用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用于为唯一交易提供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
列才能获取此信息?谢谢您的帮助。
答案 0 :(得分:1)
SQLlite具有ROW_NUMBER()
(在此处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
分期付款超过两年会出现问题。您将必须工作这一部分。我会在一个函数中编写这段代码(例如……),这样会使整个查询更加清晰。
答案 1 :(得分:1)
假设您运行的是SQLite 3.25+版本,请考虑使用CTE and window function来创建相同的 credit_card_id 和 transaction_dat e的运行计数,并使用该值添加所需的交易日期前的几个月。在此,根据新的计算日期 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
答案 2 :(得分:1)
这是一种不需要行编号的解决方案/将在较旧的SQLite(基本上支持date()的任何版本)中运行。 它仅依赖于日历表的联接(可以使用多种技术来生成,但是在链接的示例中,我只是通过创建表并直接插入查询所需的数据来生成N行)。每个月的第一天都有一行。它使用笛卡尔联接条件导致例如分3期付款的每笔付款有3行:
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')
您可以在https://www.db-fiddle.com/f/ogj2hK3cMwqp46MY6uVwX8/0
查看设置偶然地,您的问题或示例数据中有些混乱。
信用卡ID 11111111的每月付款为:
2018-01 245.89
2018-02 1562.9
2018-03 225.9
您的示例数据有3个同时付款给Micas Bar。我们知道这些是不同的,因为尽管其他数据相同,但它们具有不同的交易ID。因此,一月是75.3 + 75.3 + 75.3 + 19.99,而不仅仅是这个问题所断言的19.99 + 75.3。
要查看有关查询工作方式的更多信息,请运行非分组形式:
select
t.credit_card_id,
date(cal.d, '-1 month') as month_of_installment,
t.*
from
cal inner join transactions t on
t.transaction_date between date(cal.d, '-'||installments||' months') and cal.d
order by
t.credit_card_id,
date(cal.d, '-1 month')
我遇到的大多数DBA提倡在数据库中插入一个数字/日期表以生成诸如此类的查询-这是一种生成行序列的快速方法,如果有例如一个月没有任何交易(对于没有交易的月份,您可以将交易表加入日历表,然后得到一行总和为0的行)。在接下来的100年中生成大量的月/日行是一次简单的操作