opravy chybejicich contraints
This commit is contained in:
@@ -186,5 +186,7 @@ async def import_ote_prices(
|
|||||||
)
|
)
|
||||||
return int(n), date_str, float(first_price or 0.0), None
|
return int(n), date_str, float(first_price or 0.0), None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("OTE import DB error: %s", e)
|
detail = str(e).strip() or e.__class__.__name__
|
||||||
return -1, date_str, 0.0, f"db_import:{e.__class__.__name__}"
|
logger.error("OTE import DB error: %s", detail, exc_info=True)
|
||||||
|
short = detail[:200] if len(detail) > 200 else detail
|
||||||
|
return -1, date_str, 0.0, f"db_import:{e.__class__.__name__}: {short}"
|
||||||
|
|||||||
27
db/migration/V032__market_interval_price_primary_key.sql
Normal file
27
db/migration/V032__market_interval_price_primary_key.sql
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-- OTE import (fn_ote_import_from_json) používá ON CONFLICT (market_source, interval_start).
|
||||||
|
-- Bez odpovídajícího UNIQUE/PK PostgreSQL hlásí:
|
||||||
|
-- "there is no unique or exclusion constraint matching the ON CONFLICT specification"
|
||||||
|
-- Některé instalace (ruční DB, nestandardní pořadí migrací, restore) mohly zůstat bez PK.
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_catalog.pg_class r
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems'
|
||||||
|
AND r.relname = 'market_interval_price'
|
||||||
|
AND r.relkind = 'r'
|
||||||
|
) AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_catalog.pg_constraint c
|
||||||
|
JOIN pg_catalog.pg_class r ON r.oid = c.conrelid
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems'
|
||||||
|
AND r.relname = 'market_interval_price'
|
||||||
|
AND c.contype = 'p'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE ems.market_interval_price
|
||||||
|
ADD CONSTRAINT market_interval_price_pkey PRIMARY KEY (market_source, interval_start);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
58
db/migration/V033__telemetry_hypertable_primary_keys.sql
Normal file
58
db/migration/V033__telemetry_hypertable_primary_keys.sql
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
-- telemetry_collector: INSERT … ON CONFLICT vyžaduje UNIQUE/PK odpovídající cíli konfliktu.
|
||||||
|
-- Stejná třída problému jako u market_interval_price (V032): DB bez primárních klíčů z V001.
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_class r
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_inverter' AND r.relkind = 'r'
|
||||||
|
) AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_constraint c
|
||||||
|
JOIN pg_catalog.pg_class r ON r.oid = c.conrelid
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_inverter' AND c.contype = 'p'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE ems.telemetry_inverter
|
||||||
|
ADD CONSTRAINT telemetry_inverter_pkey PRIMARY KEY (inverter_id, measured_at);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_class r
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_ev_charger' AND r.relkind = 'r'
|
||||||
|
) AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_constraint c
|
||||||
|
JOIN pg_catalog.pg_class r ON r.oid = c.conrelid
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_ev_charger' AND c.contype = 'p'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE ems.telemetry_ev_charger
|
||||||
|
ADD CONSTRAINT telemetry_ev_charger_pkey PRIMARY KEY (charger_id, connector_id, measured_at);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_class r
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_heat_pump' AND r.relkind = 'r'
|
||||||
|
) AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM pg_catalog.pg_constraint c
|
||||||
|
JOIN pg_catalog.pg_class r ON r.oid = c.conrelid
|
||||||
|
JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace
|
||||||
|
WHERE n.nspname = 'ems' AND r.relname = 'telemetry_heat_pump' AND c.contype = 'p'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE ems.telemetry_heat_pump
|
||||||
|
ADD CONSTRAINT telemetry_heat_pump_pkey PRIMARY KEY (heat_pump_id, measured_at);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- Jeden otevřený řádek session na nabíječku (V020); bez indexu spadne ON CONFLICT v telemetry_collector.
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS uidx_ev_session_charger_open
|
||||||
|
ON ems.ev_session (charger_id)
|
||||||
|
WHERE session_end IS NULL;
|
||||||
@@ -38,33 +38,38 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
v_market_date := to_date(v_date_text, 'DD.MM.YYYY');
|
v_market_date := to_date(v_date_text, 'DD.MM.YYYY');
|
||||||
|
|
||||||
|
-- Řazení přes poddotaz: některé verze PG/rozšíření hlásí 42P10 při ORDER BY
|
||||||
|
-- přímo v RETURN QUERY set-returning funkce volané z INSERT ... SELECT.
|
||||||
RETURN QUERY
|
RETURN QUERY
|
||||||
WITH price_line AS (
|
SELECT s.interval_start, s.interval_end, s.raw_price_czk_kwh
|
||||||
-- Správná série: 15min ceny (tooltip rozlišuje od Množství a 60min)
|
FROM (
|
||||||
SELECT dl
|
WITH price_line AS (
|
||||||
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
SELECT dl
|
||||||
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_15m_price_tooltip'
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
||||||
LIMIT 1
|
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_15m_price_tooltip'
|
||||||
),
|
LIMIT 1
|
||||||
points AS (
|
),
|
||||||
|
points AS (
|
||||||
|
SELECT
|
||||||
|
(p ->> 'x')::int AS block_no,
|
||||||
|
(p ->> 'y')::numeric AS price_eur_mwh
|
||||||
|
FROM price_line pl
|
||||||
|
CROSS JOIN LATERAL jsonb_array_elements(pl.dl -> 'point') AS p
|
||||||
|
)
|
||||||
SELECT
|
SELECT
|
||||||
(p ->> 'x')::int AS block_no,
|
((v_market_date::timestamp
|
||||||
(p ->> 'y')::numeric AS price_eur_mwh
|
+ ((block_no - 1) * INTERVAL '15 minutes'))
|
||||||
FROM price_line pl
|
AT TIME ZONE 'Europe/Prague') AS interval_start,
|
||||||
CROSS JOIN LATERAL jsonb_array_elements(pl.dl -> 'point') AS p
|
((v_market_date::timestamp
|
||||||
)
|
+ (block_no * INTERVAL '15 minutes'))
|
||||||
SELECT
|
AT TIME ZONE 'Europe/Prague') AS interval_end,
|
||||||
((v_market_date::timestamp
|
ROUND(
|
||||||
+ ((block_no - 1) * INTERVAL '15 minutes'))
|
(price_eur_mwh * in_czk_per_eur / 1000.0)::numeric, 6
|
||||||
AT TIME ZONE 'Europe/Prague') AS interval_start,
|
)::numeric(10,6) AS raw_price_czk_kwh,
|
||||||
((v_market_date::timestamp
|
block_no
|
||||||
+ (block_no * INTERVAL '15 minutes'))
|
FROM points
|
||||||
AT TIME ZONE 'Europe/Prague') AS interval_end,
|
) AS s
|
||||||
ROUND(
|
ORDER BY s.block_no;
|
||||||
(price_eur_mwh * in_czk_per_eur / 1000.0)::numeric, 6
|
|
||||||
)::numeric(10,6) AS raw_price_czk_kwh
|
|
||||||
FROM points
|
|
||||||
ORDER BY block_no;
|
|
||||||
|
|
||||||
IF NOT FOUND THEN
|
IF NOT FOUND THEN
|
||||||
RAISE EXCEPTION
|
RAISE EXCEPTION
|
||||||
|
|||||||
Reference in New Issue
Block a user