Ready
This commit is contained in:
commit
95cacc79c2
34 files changed
+1394
No files matched your search
@@ -0,0 +1,30 @@
|
||||
-- Сигнал: день > 3 средних за предыдущие 7 календарных дней.
|
||||
-- Требуется 7 дней истории и ненулевая базовая сумма; пропущенные дни = 0.
|
||||
-- Целочисленное сравнение через quotient/remainder исключает overflow
|
||||
-- при умножении большой SQLite INTEGER суммы на 3 или 7.
|
||||
WITH RECURSIVE calendar(day) AS (
|
||||
SELECT MIN(order_date) FROM facts HAVING COUNT(*) > 0
|
||||
UNION ALL
|
||||
SELECT date(day, '+1 day') FROM calendar
|
||||
WHERE day < (SELECT MAX(order_date) FROM facts)
|
||||
), totals AS (
|
||||
SELECT order_date, SUM(revenue_kopecks) AS revenue_kopecks
|
||||
FROM daily_category GROUP BY order_date
|
||||
), filled AS (
|
||||
SELECT day AS order_date, COALESCE(revenue_kopecks, 0) AS revenue_kopecks
|
||||
FROM calendar LEFT JOIN totals ON totals.order_date = calendar.day
|
||||
), baseline AS (
|
||||
SELECT *, SUM(revenue_kopecks) OVER w AS previous_7_sum_kopecks,
|
||||
COUNT(*) OVER w AS history_days
|
||||
FROM filled WINDOW w AS (ORDER BY order_date ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING)
|
||||
), thresholds AS (
|
||||
SELECT *, (previous_7_sum_kopecks / 7) * 3
|
||||
+ ((previous_7_sum_kopecks % 7) * 3) / 7 AS threshold_floor_kopecks
|
||||
FROM baseline
|
||||
)
|
||||
SELECT order_date, revenue_kopecks, previous_7_sum_kopecks,
|
||||
threshold_floor_kopecks
|
||||
FROM thresholds
|
||||
WHERE history_days = 7 AND previous_7_sum_kopecks > 0
|
||||
AND revenue_kopecks > threshold_floor_kopecks
|
||||
ORDER BY order_date;
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Календарь от первого до последнего факта, отсутствующие дни дают 0.
|
||||
-- На пустой БД результат пуст; изменение первого дня NULL (нет предшественника).
|
||||
WITH RECURSIVE calendar(day) AS (
|
||||
SELECT MIN(order_date) FROM facts HAVING COUNT(*) > 0
|
||||
UNION ALL
|
||||
SELECT date(day, '+1 day') FROM calendar
|
||||
WHERE day < (SELECT MAX(order_date) FROM facts)
|
||||
), totals AS (
|
||||
SELECT order_date, SUM(revenue_kopecks) AS revenue_kopecks
|
||||
FROM daily_category GROUP BY order_date
|
||||
), filled AS (
|
||||
SELECT day AS order_date, COALESCE(revenue_kopecks, 0) AS revenue_kopecks
|
||||
FROM calendar LEFT JOIN totals ON totals.order_date = calendar.day
|
||||
)
|
||||
SELECT order_date, revenue_kopecks,
|
||||
revenue_kopecks - LAG(revenue_kopecks) OVER (ORDER BY order_date)
|
||||
AS change_kopecks
|
||||
FROM filled ORDER BY order_date;
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Execute bundled analytical SQL against SQLite read-only, write real CSVs."""
|
||||
import argparse
|
||||
import csv
|
||||
from pathlib import Path
|
||||
import sqlite3
|
||||
|
||||
QUERY_NAMES = ('top_categories', 'daily_dynamics', 'anomalies')
|
||||
|
||||
|
||||
def run_queries(db, output):
|
||||
output = Path(output)
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
uri = Path(db).resolve().as_uri() + '?mode=ro'
|
||||
counts = {}
|
||||
with sqlite3.connect(uri, uri=True) as connection:
|
||||
# One read snapshot keeps reports mutually consistent if a writer runs.
|
||||
connection.execute('BEGIN')
|
||||
for name in QUERY_NAMES:
|
||||
sql = (Path(__file__).parent / f'{name}.sql').read_text(encoding='utf-8')
|
||||
cursor = connection.execute(sql)
|
||||
rows = cursor.fetchall()
|
||||
with (output / f'{name}.csv').open('w', encoding='utf-8', newline='') as stream:
|
||||
writer = csv.writer(stream)
|
||||
writer.writerow([column[0] for column in cursor.description])
|
||||
writer.writerows(rows)
|
||||
counts[name] = len(rows)
|
||||
return counts
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--db', type=Path, required=True)
|
||||
parser.add_argument('--output', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
print(run_queries(args.db, args.output))
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Все категории по выручке RUB kopecks, при равенстве сортировка по имени.
|
||||
SELECT category, SUM(revenue_kopecks) AS revenue_kopecks
|
||||
FROM daily_category
|
||||
GROUP BY category
|
||||
ORDER BY revenue_kopecks DESC, category;
|
||||
Reference in new issue
Block a user