Нормализация недельной нормы (3.28.0)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m29s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m29s
This commit is contained in:
@@ -3381,7 +3381,7 @@ func (a *App) initPlayLifeDB() error {
|
||||
goal_week INTEGER NOT NULL,
|
||||
min_goal_score NUMERIC(10,4) NOT NULL DEFAULT 0,
|
||||
max_goal_score NUMERIC(10,4),
|
||||
actual_score NUMERIC(10,4) DEFAULT 0,
|
||||
max_score NUMERIC(10,4),
|
||||
priority SMALLINT,
|
||||
CONSTRAINT weekly_goals_project_id_goal_year_goal_week_key UNIQUE (project_id, goal_year, goal_week)
|
||||
)
|
||||
@@ -3432,6 +3432,11 @@ func (a *App) initPlayLifeDB() error {
|
||||
return fmt.Errorf("failed to create weekly_goals table: %w", err)
|
||||
}
|
||||
|
||||
// Авто-миграция weekly_goals: убираем неиспользуемый actual_score и добавляем max_score (snapshot)
|
||||
// Делаем через ALTER, чтобы работало на уже существующих БД без ручного прогона SQL-миграций.
|
||||
a.DB.Exec("ALTER TABLE weekly_goals DROP COLUMN IF EXISTS actual_score")
|
||||
a.DB.Exec("ALTER TABLE weekly_goals ADD COLUMN IF NOT EXISTS max_score NUMERIC(10,4)")
|
||||
|
||||
if _, err := a.DB.Exec(createWeeklyGoalsIndex); err != nil {
|
||||
log.Printf("Warning: Failed to create weekly_goals index: %v", err)
|
||||
}
|
||||
@@ -3446,7 +3451,11 @@ func (a *App) initPlayLifeDB() error {
|
||||
p.id AS project_id,
|
||||
agg.report_year,
|
||||
agg.report_week,
|
||||
COALESCE(agg.total_score, 0.0000) AS total_score
|
||||
COALESCE(agg.total_score, 0.0000) AS total_score,
|
||||
CASE
|
||||
WHEN wg.max_score IS NULL THEN COALESCE(agg.total_score, 0.0000)
|
||||
ELSE LEAST(COALESCE(agg.total_score, 0.0000), wg.max_score)
|
||||
END AS normalized_total_score
|
||||
FROM
|
||||
projects p
|
||||
LEFT JOIN
|
||||
@@ -3464,6 +3473,11 @@ func (a *App) initPlayLifeDB() error {
|
||||
1, 2, 3
|
||||
) agg
|
||||
ON p.id = agg.project_id
|
||||
LEFT JOIN
|
||||
weekly_goals wg
|
||||
ON wg.project_id = p.id
|
||||
AND wg.goal_year = agg.report_year
|
||||
AND wg.goal_week = agg.report_week
|
||||
WHERE
|
||||
p.deleted = FALSE
|
||||
ORDER BY
|
||||
@@ -5164,11 +5178,11 @@ func (a *App) setupWeeklyGoals() error {
|
||||
-- Считаем медиану на основе данных за 3 месяца (12 недель), исключая текущую неделю
|
||||
SELECT
|
||||
project_id,
|
||||
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY total_score) AS median_score
|
||||
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY normalized_total_score) AS median_score
|
||||
FROM (
|
||||
SELECT
|
||||
project_id,
|
||||
total_score,
|
||||
normalized_total_score,
|
||||
report_year,
|
||||
report_week,
|
||||
-- Нумеруем недели от новых к старым
|
||||
@@ -5190,6 +5204,7 @@ func (a *App) setupWeeklyGoals() error {
|
||||
goal_week,
|
||||
min_goal_score,
|
||||
max_goal_score,
|
||||
max_score,
|
||||
priority
|
||||
)
|
||||
SELECT
|
||||
@@ -5205,6 +5220,13 @@ func (a *App) setupWeeklyGoals() error {
|
||||
WHEN p.priority = 2 THEN gm.median_score * 1.3
|
||||
ELSE gm.median_score * 1.2
|
||||
END AS max_goal_score,
|
||||
-- max_score (snapshot) заполняется при INSERT, но НЕ обновляется при конфликте
|
||||
CASE
|
||||
WHEN gm.median_score IS NULL THEN NULL
|
||||
WHEN p.priority = 1 THEN gm.median_score * 1.5
|
||||
WHEN p.priority = 2 THEN gm.median_score * 1.3
|
||||
ELSE gm.median_score * 1.2
|
||||
END AS max_score,
|
||||
p.priority
|
||||
FROM projects p
|
||||
CROSS JOIN current_info ci
|
||||
@@ -5511,7 +5533,11 @@ func (a *App) recreateMaterializedViewHandler(w http.ResponseWriter, r *http.Req
|
||||
p.id AS project_id,
|
||||
agg.report_year,
|
||||
agg.report_week,
|
||||
COALESCE(agg.total_score, 0.0000) AS total_score
|
||||
COALESCE(agg.total_score, 0.0000) AS total_score,
|
||||
CASE
|
||||
WHEN wg.max_score IS NULL THEN COALESCE(agg.total_score, 0.0000)
|
||||
ELSE LEAST(COALESCE(agg.total_score, 0.0000), wg.max_score)
|
||||
END AS normalized_total_score
|
||||
FROM
|
||||
projects p
|
||||
LEFT JOIN
|
||||
@@ -5529,6 +5555,11 @@ func (a *App) recreateMaterializedViewHandler(w http.ResponseWriter, r *http.Req
|
||||
1, 2, 3
|
||||
) agg
|
||||
ON p.id = agg.project_id
|
||||
LEFT JOIN
|
||||
weekly_goals wg
|
||||
ON wg.project_id = p.id
|
||||
AND wg.goal_year = agg.report_year
|
||||
AND wg.goal_week = agg.report_week
|
||||
WHERE
|
||||
p.deleted = FALSE
|
||||
ORDER BY
|
||||
|
||||
Reference in New Issue
Block a user