sqlite3生成具有重复字段值的运行总计

时间:2019-01-11 20:21:21

标签: sqlite

这让我发疯,因为我觉得应该可以。但是我公认我不是一个巨大的SQL天才。

我有一个sqlite3表,看起来基本上是这样的:

id    date        amount
--    ----        ------
51    2018.10.01    10.0
52    2018.11.15   100.0
53    2018.11.15    20.0
54    2018.09.10   -30.0

(至少,这些是相关的字段;其他字段已被忽略)。

我想做的是生成amount列的运行总计,但数据按date排序。

我知道用于计算运行总计的“将表与自身连接起来”的技巧。因此,如果我想为每个id(一个唯一的字段)提供一个新的运行总价值,我可以这样做:

select T2.id, T2.date, T2.amount, sum(T2.amount)
from Transactions T1
inner join Transactions T2
on T1.id >= T2.id
group by T1.id

我明白了:

"51"    "2018.10.01"    "10.0"  "10.0"
"52"    "2018.11.15"    "100.0" "110.0"
"53"    "2018.11.15"    "20.0"  "130.0"
"54"    "2018.09.10"    "-30.0" "100.0"

运行总正确。

但是,如果我希望以date的顺序运行此数据的总计,则会发生故障。这很接近:

select T1.id, T2.date, T2.amount, sum(T2.amount)
from Transactions T1
inner join Transactions T2
on T1.date >= T2.date
group by T1.date

除了在amountdate的两行中对2018.11.15值进行计数(并合并)之外。大概是因为on T1.date >= T2.date子句适用于两行,每行两次。

"54"    "2018.09.10"    "-30.0" "-30.0"
"51"    "2018.09.10"    "-30.0" "-20.0"
"53"    "2018.09.10"    "-30.0" "200.0"

如我所见,只有在对值都是唯一且已排序的字段执行join时,此技术才有效。一旦我按date对表格进行排序,唯一的id值就会乱序并且不再可用。

因此,我想到了-也许首先按date对表进行排序,然后添加一个临时表,其中包含唯一的排序数字。只需行号即可。

不幸的是,这似乎是不支持row_number()rownumover子句中任何一种的sqlite版本。

我知道这种生成行号的技术:

select id, date,
(select count(*) from Transactions T1 where T1.id <= T2.id)
from Transactions T2

"51"    "2018.10.01"    "1"
"52"    "2018.11.15"    "2"
"53"    "2018.11.15"    "3"
"54"    "2018.09.10"    "4"

但是我几乎没有摆弄任何办法:

  • 首先按date
  • 对表格进行排序
  • 然后使用count(*)技术生成唯一的行号
  • 然后join与其自身的表一起创建运行总计

在单个SQL语句中。

希望这是有道理的。感谢任何人的任何想法。

2 个答案:

答案 0 :(得分:0)

如果您使用的是Sqlite 3.25或更高版本,则使用窗口函数可以简化此操作。示例:

首先,用示例数据填充表格:

CREATE TABLE example(id INTEGER PRIMARY KEY, date TEXT, amount REAL);
INSERT INTO example VALUES(51,'2018-10-01',10.0);
INSERT INTO example VALUES(52,'2018-11-15',100.0);
INSERT INTO example VALUES(53,'2018-11-15',20.0);
INSERT INTO example VALUES(54,'2018-09-10',-30.0);

(请注意,我将日期格式更改为sqlite日期和时间功能可以理解的格式,因为这样一来,您想进行比排序更复杂的操作就可以使工作变得更加轻松。)

查询

SELECT *, sum(amount) OVER (ORDER BY date, id) AS running_total
FROM example
ORDER BY date, id;

产生:

id          date        amount      running_total
----------  ----------  ----------  -------------
54          2018-09-10  -30.0       -30.0        
51          2018-10-01  10.0        -20.0        
52          2018-11-15  100.0       80.0         
53          2018-11-15  20.0        100.0     

如果您使用的是较旧的版本,则您真正应该考虑升级的原因不仅仅是拥有窗口功能。

答案 1 :(得分:0)

谢谢肖恩(Shawn)–您使我步入正轨。

它看起来像是针对SQLite的DB浏览器的最新beta版本确实支持窗口功能(我想是因为最新版本的SQLite本身支持)。

问题解决了!