WITH RECURSIVE calendar(day, last_day) AS ( SELECT MIN(order_date), MAX(order_date) FROM daily_category_revenue HAVING COUNT(*) > 0 UNION ALL SELECT date(day, '+1 day'), last_day FROM calendar WHERE day < last_day ), categories AS ( SELECT DISTINCT category FROM daily_category_revenue ), daily AS ( SELECT day, c.category, COALESCE(r.revenue_kopecks, 0) AS revenue_kopecks FROM calendar CROSS JOIN categories AS c LEFT JOIN daily_category_revenue AS r ON r.order_date = day AND r.category = c.category ), -- Вычитаем общий для категории минимум в целых копейках до перехода AVG к REAL. -- Такой сдвиг сохраняет отклонения и различия в копейку при большом базовом уровне. shifted AS ( SELECT *, revenue_kopecks - MIN(revenue_kopecks) OVER (PARTITION BY category) AS amount FROM daily ), deviations AS ( SELECT *, amount - AVG(amount) OVER (PARTITION BY category) AS deviation FROM shifted ), stats AS ( SELECT *, COUNT(*) OVER (PARTITION BY category) AS days, AVG(deviation * deviation) OVER (PARTITION BY category) AS variance FROM deviations ) SELECT day AS order_date, category, revenue_kopecks FROM stats WHERE days >= 7 AND variance > 0 AND deviation * deviation > 4 * variance ORDER BY day, category;