How do I calculate a running SUM on a SQLite query?
As of SQLite 3.25.0, since 2018-09-15, window functions and their keyword OVER
are supported. The answer to your question is now easy:
SELECT Country, Gdp, SUM(Gdp) OVER (ROWS UNBOUNDED PRECEDING)
FROM CountryGdp;
This is the minimal query that does what you request, but it doesn't define any ordering so here is a more proper way of doing it.
SELECT
Country,
Gdp,
SUM(Gdp) OVER (
ORDER BY Country -- Window ordering (not necessarily the same as result ordering!)
ROWS BETWEEN -- Window for the SUM includes these rows:
UNBOUNDED PRECEDING -- all rows before current one in window ordering
AND CURRENT ROW -- up to and including current row.
) AS RunningTotal
FROM CountryGdp
ORDER BY Country;
In any way, the query should run in O(N) time.
Cross join solutions like Diomidis Spinellis suggested take O(N^2) time. A recursive CTE can work faster, if you can stomach the convoluted code.
This produces the same output as his.
WITH RECURSIVE running(id, name, gdppc, rt) AS (
SELECT row1._rowid_, row1.name, row1.gdppc, COALESCE(row1.gdppc,0)
FROM gdppc AS row1
WHERE row1._rowid_ = (
SELECT a._rowid_
FROM gdppc AS a
ORDER BY a.gdppc, a.name, a._rowid_
LIMIT 1)
UNION ALL
SELECT row_n._rowid_, row_n.name, row_n.gdppc, COALESCE(row_n.gdppc,0)+running.rt
FROM gdppc AS row_n INNER JOIN running
ON row_n._rowid_ = (
SELECT a._rowid_
FROM gdppc AS a
WHERE (a.gdppc, a.name, a._rowid_) > (running.gdppc, running.name, running.id)
ORDER BY a.gdppc, a.name, a._rowid_
LIMIT 1))
SELECT running.name, running.gdppc, running.rt
FROM running;
Ordering and comparisons take care of duplicates, COALESCE
is there to ignore NULLs.
If you have a good index, this should be O(N log N). Since SQLite doesn't support cursors, an O(N) solution probably doesn't exist without relying on an external application.
You can do it by joining the table with itself (performing a so-called Cartesian or cross join). See the following example.
SELECT a.name, a.gdppc, SUM(b.gdppc)
FROM gdppc AS a, gdppc AS b WHERE b.gdppc <= a.gdppc
GROUP BY b.id ORDER BY a.gdppc;
Given a table containing countries and their per capita GDP it will give you a running total of the GDP figure.
Democratic Republic of Congo|329.645|329.645
Zimbabwe|370.465|700.11
Liberia|385.417|1085.527
Burundi|399.657|1485.184
Eritrea|678.954|2164.138
Niger|711.877|2876.015
Central African Republic|743.945|3619.96
Sierra Leone|781.594|4401.554
Togo|833.803|5235.357
Malawi|867.063|6102.42
Mozambique|932.511|7034.931
...
Note that this can be a very resource-intensive operation, because if a table has N elements it will create a temporary table with N*N elements. I would not perform it on a large table.