Как вычислить запущенный СУММ по SQLite-запросу?

Как получить столбец, который является суммой всех значений перед другим столбцом?

Ответ 1

Вы можете сделать это, присоединившись к таблице с собой (выполняя так называемое декартовое или cross join). См. Следующий пример.

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;

Учитывая таблицу, содержащую страны и их ВВП на душу населения, она даст вам общее количество ВВП.

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
...

Обратите внимание, что это может быть очень ресурсоемкая операция, потому что если в таблице есть N элементов, она создаст временную таблицу с элементами N * N. Я бы не выполнил его на большом столе.

Ответ 2

Решения с перекрестным соединением, такие как Диомидис Спинеллис предложили занять O (N ^ 2) время. Рекурсивный CTE может работать быстрее, если вы можете справиться с запутанным кодом.

Это дает тот же результат, что и его.

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;

Упорядочение и сравнение учитывают дубликаты, COALESCE здесь, чтобы игнорировать NULL.

Если у вас хороший индекс, это должно быть O (N log N). Поскольку SQLite не поддерживает курсоры, решение O (N), вероятно, не существует, не полагаясь на внешнее приложение.

Ответ 3

Начиная с SQLite 3.25.0, начиная с 2018-09-15, поддерживаются оконные функции и их ключевое слово OVER. Ответ на ваш вопрос теперь прост:

SELECT Country, Gdp, SUM(Gdp) OVER (ROWS UNBOUNDED PRECEDING)
FROM CountryGdp;

Это минимальный запрос, который выполняет то, что вы запрашиваете, но он не определяет порядок, поэтому здесь есть более правильный способ сделать это.

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;

Ответ 4

Вам нужно сделать сумму в нужном вам поле. Запрос зависит от используемой вами базы данных. Oracle позволяет вам сделать это:

select id, value, sum(value) as partial_sum over (order by id) from table