new fix OTE
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
-- Repeatable migration – při změně funkce stačí upravit tento soubor
|
-- Repeatable migration – při změně funkce stačí upravit tento soubor
|
||||||
-- =============================================================
|
-- =============================================================
|
||||||
|
|
||||||
-- Parser: raw jsonb → 96 cenových řádků
|
-- Parser: raw jsonb → 96 (nebo 92/100 při DST) cenových řádků po 15 min
|
||||||
CREATE OR REPLACE FUNCTION ems.fn_ote_parse_15m_price_json(
|
CREATE OR REPLACE FUNCTION ems.fn_ote_parse_15m_price_json(
|
||||||
in_payload jsonb,
|
in_payload jsonb,
|
||||||
in_czk_per_eur numeric DEFAULT 25.000
|
in_czk_per_eur numeric DEFAULT 25.000
|
||||||
@@ -19,6 +19,8 @@ AS $$
|
|||||||
DECLARE
|
DECLARE
|
||||||
v_date_text text;
|
v_date_text text;
|
||||||
v_market_date date;
|
v_market_date date;
|
||||||
|
v_dl jsonb;
|
||||||
|
v_npts int;
|
||||||
BEGIN
|
BEGIN
|
||||||
IF in_payload IS NULL THEN
|
IF in_payload IS NULL THEN
|
||||||
RAISE EXCEPTION 'in_payload must not be null';
|
RAISE EXCEPTION 'in_payload must not be null';
|
||||||
@@ -38,24 +40,53 @@ 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
|
-- OTE mění strukturu: novější data = 15min série (tooltip flash_chart_01_y_15m_*),
|
||||||
-- přímo v RETURN QUERY set-returning funkce volané z INSERT ... SELECT.
|
-- starší / jiná odpověď = jen 24 hodinových bodů s tooltip "Cena".
|
||||||
|
SELECT t.dl INTO v_dl
|
||||||
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
||||||
|
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_15m_price_tooltip'
|
||||||
|
AND jsonb_array_length(dl -> 'point') >= 90
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
IF v_dl IS NULL THEN
|
||||||
|
SELECT t.dl INTO v_dl
|
||||||
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
||||||
|
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_60m_price_tooltip'
|
||||||
|
AND jsonb_array_length(dl -> 'point') >= 90
|
||||||
|
LIMIT 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF v_dl IS NULL THEN
|
||||||
|
SELECT t.dl INTO v_dl
|
||||||
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
||||||
|
WHERE dl ->> 'tooltip' = 'Cena'
|
||||||
|
AND jsonb_array_length(dl -> 'point') BETWEEN 20 AND 28
|
||||||
|
LIMIT 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF v_dl IS NULL THEN
|
||||||
|
SELECT t.dl INTO v_dl
|
||||||
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
||||||
|
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_15m_price_tooltip'
|
||||||
|
AND jsonb_array_length(dl -> 'point') BETWEEN 20 AND 28
|
||||||
|
LIMIT 1;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF v_dl IS NULL THEN
|
||||||
|
RAISE EXCEPTION
|
||||||
|
'OTE price dataLine not found (očekáváno 15min flash_* nebo hodinová Cena); '
|
||||||
|
'dostupné tooltips: %',
|
||||||
|
(SELECT jsonb_agg(dl ->> 'tooltip' ORDER BY dl ->> 'tooltip')
|
||||||
|
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') dl);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
v_npts := jsonb_array_length(v_dl -> 'point');
|
||||||
|
|
||||||
|
IF v_npts >= 90 THEN
|
||||||
|
-- x = 1..N = 15min bloky (typicky 96; 92/100 při přechodu letní/zimní čas)
|
||||||
RETURN QUERY
|
RETURN QUERY
|
||||||
SELECT s.interval_start, s.interval_end, s.raw_price_czk_kwh
|
SELECT s.interval_start, s.interval_end, s.raw_price_czk_kwh
|
||||||
FROM (
|
FROM (
|
||||||
WITH price_line AS (
|
|
||||||
SELECT dl
|
|
||||||
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') AS t(dl)
|
|
||||||
WHERE dl ->> 'tooltip' = 'flash_chart_01_y_15m_price_tooltip'
|
|
||||||
LIMIT 1
|
|
||||||
),
|
|
||||||
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
|
||||||
((v_market_date::timestamp
|
((v_market_date::timestamp
|
||||||
+ ((block_no - 1) * INTERVAL '15 minutes'))
|
+ ((block_no - 1) * INTERVAL '15 minutes'))
|
||||||
@@ -67,16 +98,42 @@ BEGIN
|
|||||||
(price_eur_mwh * in_czk_per_eur / 1000.0)::numeric, 6
|
(price_eur_mwh * in_czk_per_eur / 1000.0)::numeric, 6
|
||||||
)::numeric(10,6) AS raw_price_czk_kwh,
|
)::numeric(10,6) AS raw_price_czk_kwh,
|
||||||
block_no
|
block_no
|
||||||
FROM points
|
FROM (
|
||||||
|
SELECT
|
||||||
|
(p ->> 'x')::int AS block_no,
|
||||||
|
(p ->> 'y')::numeric AS price_eur_mwh
|
||||||
|
FROM jsonb_array_elements(v_dl -> 'point') AS p
|
||||||
|
) pts
|
||||||
) AS s
|
) AS s
|
||||||
ORDER BY s.block_no;
|
ORDER BY s.block_no;
|
||||||
|
ELSE
|
||||||
|
-- x = 1..24 = hodiny dne; každou hodinovou cenu rozvineme na 4× 15min slot
|
||||||
|
RETURN QUERY
|
||||||
|
SELECT s.interval_start, s.interval_end, s.raw_price_czk_kwh
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
((v_market_date::timestamp
|
||||||
|
+ (((hour_no - 1) * 4 + qix) * INTERVAL '15 minutes'))
|
||||||
|
AT TIME ZONE 'Europe/Prague') AS interval_start,
|
||||||
|
((v_market_date::timestamp
|
||||||
|
+ (((hour_no - 1) * 4 + qix) * INTERVAL '15 minutes')
|
||||||
|
+ INTERVAL '15 minutes')
|
||||||
|
AT TIME ZONE 'Europe/Prague') AS interval_end,
|
||||||
|
ROUND(
|
||||||
|
(price_eur_mwh * in_czk_per_eur / 1000.0)::numeric, 6
|
||||||
|
)::numeric(10,6) AS raw_price_czk_kwh,
|
||||||
|
(hour_no - 1) * 4 + qix + 1 AS sort_key
|
||||||
|
FROM (
|
||||||
|
SELECT (p ->> 'x')::int AS hour_no, (p ->> 'y')::numeric AS price_eur_mwh
|
||||||
|
FROM jsonb_array_elements(v_dl -> 'point') AS p
|
||||||
|
) h
|
||||||
|
CROSS JOIN (VALUES (0), (1), (2), (3)) AS q(qix)
|
||||||
|
) AS s
|
||||||
|
ORDER BY s.sort_key;
|
||||||
|
END IF;
|
||||||
|
|
||||||
IF NOT FOUND THEN
|
IF NOT FOUND THEN
|
||||||
RAISE EXCEPTION
|
RAISE EXCEPTION 'OTE price series had no points after parse';
|
||||||
'dataLine tooltip=flash_chart_01_y_15m_price_tooltip not found; '
|
|
||||||
'dostupné tooltips: %',
|
|
||||||
(SELECT jsonb_agg(dl ->> 'tooltip')
|
|
||||||
FROM jsonb_array_elements(in_payload #> '{data,dataLine}') dl);
|
|
||||||
END IF;
|
END IF;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
@@ -84,10 +141,10 @@ $$;
|
|||||||
COMMENT ON FUNCTION ems.fn_ote_parse_15m_price_json(jsonb, numeric) IS
|
COMMENT ON FUNCTION ems.fn_ote_parse_15m_price_json(jsonb, numeric) IS
|
||||||
'Parsuje raw JSON z OTE @@chart-data?time_resolution=PT15M.
|
'Parsuje raw JSON z OTE @@chart-data?time_resolution=PT15M.
|
||||||
Datum extrahuje z graph.title (DD.MM.YYYY).
|
Datum extrahuje z graph.title (DD.MM.YYYY).
|
||||||
Série: flash_chart_01_y_15m_price_tooltip (EUR/MWh → Kč/kWh přes kurz).
|
Výběr série: (1) flash_chart_01_y_15m_price_tooltip s ≥90 body, (2) flash_chart_01_y_60m_price_tooltip s ≥90,
|
||||||
Výstup: 96 řádků, interval_start/end jako timestamptz (UTC), cena Kč/kWh.
|
(3) tooltip Cena s 20–28 body (hodinovka → 4× 15min stejná EUR/MWh), (4) legacy 15m tooltip s 20–28 body.
|
||||||
|
EUR/MWh → Kč/kWh přes kurz. Výstup: řádky po 15 min (typicky 96).
|
||||||
Testování přímo v DB:
|
Testování přímo v DB:
|
||||||
COPY tmp_ote FROM ''/tmp/ote.json'';
|
|
||||||
SELECT * FROM ems.fn_ote_parse_15m_price_json(pg_read_file(''/tmp/ote.json'')::jsonb, 25.0) LIMIT 5;';
|
SELECT * FROM ems.fn_ote_parse_15m_price_json(pg_read_file(''/tmp/ote.json'')::jsonb, 25.0) LIMIT 5;';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user