SQLite中的聚合

问题描述 投票:3回答:3

我期待构建一个SQL查询,它能够按月汇总分期值。通常这不会太难,因为你只需要分期付款和group by月份。然而,问题并不那么容易,在帖子的其他部分,我将说明原因并征求人们能够提供的任何帮助。

首先,重要的是要注意installments列。如果installments为1,则表示在购买时支付总价值。如果installments大于1,这意味着总价值在当月和下个月支付。例如,如果我们看到transaction_id 9和10,这是100美元的交易,有2期分期付款,这意味着2月份将支付50美元,3月份将支付50美元。

考虑一下,我们希望看到credit_card_id = 11111111的每月账单。如果我们查看installments列,我们可以看到正确的输出应该如下:

  • 1月:19.99 + 75.3
  • 二月:1337 + 75.3
  • 三月:75.3

同样,为了清楚起见,3月份的75.3是因为我们在1月份进行了3次分期交易,这意味着客户将在1月,2月和3月收取75.3的费用。问题是我不知道如何根据给定的数据创建March的类别。

Transactions

首先,我在SQL中重新创建了表,并且可以通过以下SQLite查询轻松地按月获取卡的所有事务

select strftime('%m', transaction_date) as Month, total_value, installment_value, installments 
from transactions 
WHERE credit_card_id = '11111111';

它输出一个看起来像这个output的表

但是,如何将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);

我的问题是

  1. 是否有可能在SQLite中获得我在上面确定的格式的输出,如果是,如何?
  2. 我是否必须拥有txn专栏才能获得此信息?

谢谢您的帮助。

sql database sqlite aggregate-functions data-analysis
3个回答
1
投票

假设您运行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


1
投票

SQLite有qazxsw poi(点击这里qazxsw poi)。

ROW_NUMBER()

分期付款超过两年时会出现问题。你将不得不工作那部分。我会在函数中编写这个代码(如果......),它会使整个查询更清晰。


1
投票

这是一个不需要行编号的解决方案/将在更老的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年中产生一堆几个月/几天的行是一个微不足道的一次性操作

© www.soinside.com 2019 - 2024. All rights reserved.