Предполагая, что rec является автоматически генерируемым целочисленным первичным ключом (и что дубликат rec 5 является опечаткой), так что чем меньше ключ, тем старше журнал, этот подход работает с Sqlite 3.25 и новее:
-- Create table and populate with sample data.
CREATE TABLE logs(rec INTEGER PRIMARY KEY AUTOINCREMENT
, storage TEXT
, name TEXT
, size INTEGER
, status TEXT);
INSERT INTO logs VALUES(1,'x','pip',85,'discarded');
INSERT INTO logs VALUES(2,'x','foo',25,'available');
INSERT INTO logs VALUES(3,'x','bla',45,'available');
INSERT INTO logs VALUES(4,'x','bar',35,'available');
INSERT INTO logs VALUES(5,'x','wow',50,'available');
INSERT INTO logs VALUES(6,'z','sid',25,'available');
(Я обычно не фанат использования AUTOINCREMENT
с sqlite3, но это один из случаев, когда он необходим, так как он предотвращает повторное использование сгенерированных строк. Очень маловероятно, что это произойдет без него, нодавайте будем параноиком.)
Этот запрос вычисляет общий размер всех доступных журналов в определенной категории хранения, причем общее количество ограничено текущим журналом и всеми более новыми (с более высокими значениями).Требуется 3.25 или лучше, потому что именно тогда оконные функции были добавлены в sqlite.
SELECT *
, sum(size) OVER (PARTITION BY storage
ORDER BY rec
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
AS total_size
FROM logs
WHERE status = 'available'
ORDER BY rec;
производит:
rec storage name size status total_size
---------- ---------- ---------- ---------- ---------- -----------
2 x foo 25 available 155
3 x bla 45 available 130
4 x bar 35 available 85
5 x wow 50 available 50
6 z sid 25 available 25
Чтобы получить только строки со столбцом total_size
больше 100,оно должно быть заключено в общее табличное выражение, потому что вы не можете использовать значения, сгенерированные оконной функцией, в предложениях WHERE
:
WITH running_totals AS
(SELECT *
, sum(size) OVER (PARTITION BY storage
ORDER BY rec
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
AS total_size
FROM logs
WHERE status = 'available')
SELECT * FROM running_totals WHERE total_size > 100 ORDER BY rec;
Это приводит к:
rec storage name size status total_size
---------- ---------- ---------- ---------- ---------- -----------
2 x foo 25 available 155
3 x bla 45 available 130
записи, которые вы хотели.Чтобы пометить эти строки как отброшенные, вы также можете использовать CTE с операторами UPDATE:
WITH running_totals AS
(SELECT rec
, sum(size) OVER (PARTITION BY storage
ORDER BY rec
RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)
AS total_size
FROM logs
WHERE status = 'available')
UPDATE logs
SET status = 'discarded'
WHERE rec IN (SELECT rec FROM running_totals WHERE total_size > 100);