BSL – SQL-kommandon (Supabase)

Viktigt: datum och natt_datum är generated columns

datum och natt_datum i garmin_puls/garmin_stress/garmin_puls_stress beräknas automatiskt av Supabase från lokal_tid. De kan aldrig bli fel och ska ALDRIG uppdateras manuellt.


Diagnostik

Antal poster per datum i garmin_puls (kalenderdatum)

SELECT datum, COUNT(*) as antal_rader
FROM garmin_puls
WHERE user_id = 1
GROUP BY datum
ORDER BY datum;

Antal poster per natt_datum

SELECT natt_datum, COUNT(*) as antal_rader
FROM garmin_puls
WHERE user_id = 1
GROUP BY natt_datum
ORDER BY natt_datum;

Täckning per timme för ett specifikt datum

SELECT EXTRACT(HOUR FROM lokal_tid) AS timme, COUNT(*) AS antal
FROM garmin_puls
WHERE lokal_tid >= '2026-05-06 00:00:00'
  AND lokal_tid <  '2026-05-07 00:00:00'
  AND user_id = 1
GROUP BY timme
ORDER BY timme;

Kontrollera :44-artefakter per datum

SELECT datum, COUNT(*) as antal_artefakter
FROM garmin_puls
WHERE user_id = 1
AND EXTRACT(SECOND FROM lokal_tid) = 44
GROUP BY datum
ORDER BY datum;

Visa alla constraints på en tabell

SELECT conname, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid = 'garmin_puls'::regclass;

Kontrollera generated columns

SELECT column_name, data_type, is_generated, generation_expression
FROM information_schema.columns
WHERE table_name IN ('garmin_puls', 'garmin_stress', 'garmin_puls_stress')
  AND column_name IN ('datum', 'natt_datum', 'lokal_tid')
ORDER BY table_name, column_name;

Kontrollera pulsdata för en specifik natt

SELECT lokal_tid, puls_bpm, natt_datum
FROM garmin_puls
WHERE natt_datum = 'YYYY-MM-DD'
  AND user_id = 1
ORDER BY lokal_tid;

Rensning

Radera :44-artefakter för specifika datum

DELETE FROM garmin_puls
WHERE user_id = 1
AND datum IN ('YYYY-MM-DD', 'YYYY-MM-DD')
AND EXTRACT(SECOND FROM lokal_tid) = 44;

Radera pulsdata för specifika natt_datum

-- OBS: använd lokal_tid-intervall för att vara exakt, inte datum
DELETE FROM garmin_puls
WHERE user_id = 1
AND natt_datum IN ('YYYY-MM-DD', 'YYYY-MM-DD');

DELETE FROM garmin_stress
WHERE user_id = 1
AND natt_datum IN ('YYYY-MM-DD', 'YYYY-MM-DD');

Töm alla garmin-tabeller (för total omuppladdning)

TRUNCATE TABLE garmin_puls, garmin_stress, garmin_puls_stress RESTART IDENTITY;

Töm daglig_logg och relaterade tabeller

TRUNCATE TABLE kost_log, huvudvark_log, daglig_logg, interventioner RESTART IDENTITY;

Struktur

Visa kolumner och typer för en tabell

SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'daglig_logg'
ORDER BY ordinal_position;

Visa UNIQUE constraints

SELECT conrelid::regclass AS tabell, conname AS constraint_namn
FROM pg_constraint
WHERE contype = 'u'
  AND conrelid::regclass::text IN
    ('daglig_logg','huvudvark_log','kost_log','interventioner','garmin_puls','garmin_stress')
ORDER BY tabell;

Index

idx_garmin_puls_user_datum

Krävs för att dag_zon_v (Graf 10) ska vara snabb. Utan detta index scannas hela tabellen vid varje sidhämtning.

CREATE INDEX IF NOT EXISTS idx_garmin_puls_user_datum
ON garmin_puls (user_id, datum);

Vyer (Views)

dag_zon_v – Dagtid pulszonandel per dag

Beräknar andelen mätningar (08–20) per pulszon och dag. Baseras på MAXPULS 170. Används av Graf 10 (Zontrend dagtid) i halsa-dashboarden.

CREATE OR REPLACE VIEW dag_zon_v AS
SELECT
  user_id,
  datum,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm < 85)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS vila,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm >= 85  AND puls_bpm < 102)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS z1_aterhämtning,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm >= 102 AND puls_bpm < 119)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS z2_aerob_bas,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm >= 119 AND puls_bpm < 136)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS z3_aerob,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm >= 136 AND puls_bpm < 153)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS z4_troskel,
  ROUND(
    COUNT(*) FILTER (WHERE puls_bpm >= 153)::numeric / NULLIF(COUNT(*),0) * 100, 2
  ) AS z5_anaerob
FROM garmin_puls
WHERE EXTRACT(HOUR FROM lokal_tid) >= 8
  AND EXTRACT(HOUR FROM lokal_tid) < 20
GROUP BY user_id, datum;

Zongränser (MAXPULS 170): Vila <85 · Z1 85–101 · Z2 102–118 · Z3 119–135 · Z4 136–152 · Z5 ≥153 bpm.


Rutin vid datumproblem

  1. Kör täcknings-SQL ovan för att identifiera drabbade timmar/datum
  2. Radera natt_datum ±1 för att täcka hela natten
  3. Kontrollera att alla WELLNESS FIT-filer för perioden finns i Indata-mappen
  4. Kör garmin_upload.py
  5. Verifiera med antal-per-timme-SQL

Noteringar