У меня есть база данных SQL, и я храню данные о транспортных средствах в таблице.Среди этих данных я храню потребление электроэнергии каждой поездки в столбце, а в другом столбце вычисляю разницу этого потребления между строками, используя функцию LAG ().
Эта функция LAG () всегда устанавливает значениеNULL первая строка (если у вас есть 10 значений, есть 9 значений разницы), это логично.
Когда я получаю разницу, я сохраняю дату последнего обновления, поэтому в следующий раз, когда я обновлю таблицу,процесс начинается с этой сохраненной даты и так далее.Моя проблема в том, что когда я обновляю таблицу новыми значениями потребления, в столбце разницы всегда есть одно новое значение NULL.
Это мой код, он работает нормально, но мне нужно получить предыдущее сохраненное значение и выполнить расчетчтобы избежать нулевых значений:
DECLARE
schemaName TEXT;
tableName TEXT;
text_var1 TEXT;
text_var2 TEXT;
text_var3 TEXT;
consulta TEXT;
tablaJoinConsumos TEXT;
tablaJoinRecuperadas TEXT;
tablaExtraJoinConsumos TEXT;
tablaExtraJoinRecuperadas TEXT;
tmpDifCon TEXT;
tmpDifConEco TEXT;
tmpDifRec TEXT;
tmpDifRecEco TEXT;
dropTablaJoinConsumos TEXT;
dropTablaJoinRecuperadas TEXT;
dropTablaExtraJoinConsumos TEXT;
dropTablaExtraJoinRecuperadas TEXT;
dropTmpDifCon TEXT;
dropTmpDifRec TEXT;
creoTablaJoinConsumos TEXT;
creoTablaJoinRecuperadas TEXT;
creoTablaExtraJoinRecuperadas TEXT;
creoTablaExtraJoinConsumos TEXT;
creoTmpDifCon TEXT;
creoTmpDifRec TEXT;
selectLastEnergiasVehicleData TEXT;
selectExtraJoinConsumos TEXT;
selectExtraJoinRecuperadas TEXT;
selectEcon TEXT;
selectErec TEXT;
updateVehicleDataCon TEXT;
updateVehicleDataRec TEXT;
registros RECORD;
energias RECORD;
ultimaFecha RECORD;
vehicleData RECORD;
diferencias RECORD;
subtrips RECORD;
col BOOLEAN;
BEGIN
RAISE NOTICE 'ESTOY EN FNC_CALCENERGIAS()';
--nombro esquema, tablas...
schemaName = CONCAT($1, '_org');
tableName = FORMAT('%s_%s_subtrip', $1, $2);
tablaJoinConsumos = FORMAT('tmp_%s_%s_join_consumida', $1, $2); --aqui guardo datos de energia consumida y consumida modo eco para despues calcular diferencias
tablaExtraJoinConsumos = FORMAT('tmp_%s_%s_extra_join_con', $1, $2);
tablaJoinRecuperadas = FORMAT('tmp_%s_%s_join_recuperada', $1, $2);
tablaExtraJoinRecuperadas = FORMAT('tmp_%s_%s_extra_join_rec', $1, $2);
tmpDifCon = FORMAT('tmp_%s_%s_difcon', $1, $2);
tmpDifRec = FORMAT('tmp_%s_%s_difrec', $1, $2);
--creo columnas de diferencias
RAISE NOTICE 'VOY A CREAR COLUMNAS DE DIFERENCIAS, SI NO EXISTEN';
col = TRUE;
EXECUTE FORMAT('SELECT FALSE FROM pg_attribute WHERE attrelid = ''%I.%I''::regclass AND attname = ''dif_energiacon'' AND NOT attisdropped AND attnum > 0',
schemaName, tableName) INTO col;
IF col IS NULL OR col THEN
-- Poner las columnas que faltan
EXECUTE FORMAT('ALTER TABLE %I.%I
ADD COLUMN dif_energiacon real DEFAULT 0,
ADD COLUMN dif_energiaconeco real DEFAULT 0,
ADD COLUMN dif_energiarec real DEFAULT 0,
ADD COLUMN dif_energiarececo real DEFAULT 0',
schemaName, tableName);
END IF;
RAISE NOTICE 'HE CREADO COLUMNAS DE DIFERENCIAS, SI NO EXISTÍAN';
--SELECTS
consulta := FORMAT('SELECT tripid, halt, seq, energiacon, energiarec, energiaconeco, energiarececo FROM %I.%I WHERE seq > 0 AND orgid = %s AND vehicleid = %s ORDER BY halt;', schemaName, tableName, $1, $2);
dropTablaJoinConsumos := FORMAT('DROP TABLE IF EXISTS %I;', tablaJoinConsumos);
dropTablaJoinRecuperadas := FORMAT('DROP TABLE IF EXISTS %I;', tablaJoinRecuperadas);
dropTablaExtraJoinConsumos := FORMAT('DROP TABLE IF EXISTS %I;', tablaExtraJoinConsumos);
dropTablaExtraJoinRecuperadas := FORMAT('DROP TABLE IF EXISTS %I;', tablaExtraJoinRecuperadas);
dropTmpDifCon := FORMAT('DROP TABLE IF EXISTS %I;', tmpDifCon);
dropTmpDifRec := FORMAT('DROP TABLE IF EXISTS %I;', tmpDifRec);
creoTablaJoinConsumos := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, consumo real, dif_consumos real, PRIMARY KEY(halt, tripid, seq, consumo));', tablaJoinConsumos);
creoTablaExtraJoinConsumos := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, dif_consumo real, PRIMARY KEY(halt, tripid, seq));', tablaExtraJoinConsumos);
creoTablaJoinRecuperadas := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, recuperada real, dif_consumos real, PRIMARY KEY(halt, tripid, seq, recuperada));', tablaJoinRecuperadas);
creoTablaExtraJoinRecuperadas := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, dif_recuperada real, PRIMARY KEY(halt, tripid, seq));', tablaExtraJoinRecuperadas);
creoTmpDifCon := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, dif_con real, PRIMARY KEY(halt, tripid, seq))', tmpDifCon);
creoTmpDifRec := FORMAT('CREATE TEMPORARY TABLE IF NOT EXISTS %I (halt timestamptz, tripid integer, seq integer, dif_rec real, PRIMARY KEY(halt, tripid, seq))', tmpDifRec);
selectExtraJoinConsumos := FORMAT('SELECT * FROM %I ORDER BY halt, seq;', tablaExtraJoinConsumos);
selectExtraJoinRecuperadas := FORMAT('SELECT * FROM %I ORDER BY halt, seq;', tablaExtraJoinRecuperadas);
selectEcon := FORMAT('SELECT tripid, halt, seq, energiacon FROM %I.%I WHERE seq > 0 AND energiacon > 0 ORDER BY halt, energiacon;', schemaName, tableName);
selectErec := FORMAT('SELECT tripid, halt, seq, energiarec FROM %I.%I WHERE seq > 0 AND energiarec > 0 ORDER BY halt, energiarec', schemaName, tableName);
selectLastEnergiasVehicleData := FORMAT('SELECT lastenergiacon, lastenergiarec FROM public.vehicle_data WHERE orgid = %s AND vehicleid = %s;', $1, $2);
--UPDATES
updateVehicleDataCon := FORMAT('UPDATE public.vehicle_data SET lastenergiacon = (SELECT halt FROM "tmp_%s_%s_difcon" ORDER BY halt DESC LIMIT 1) WHERE orgid = %s AND vehicleid = %s;', $1, $2, $1, $2);
updateVehicleDataRec := FORMAT('UPDATE public.vehicle_data SET lastenergiarec = (SELECT halt FROM "tmp_%s_%s_difrec" ORDER BY halt DESC LIMIT 1) WHERE orgid = %s AND vehicleid = %s;', $1, $2, $1, $2);
RAISE NOTICE 'DROPS';
EXECUTE dropTablaJoinConsumos;
EXECUTE dropTablaJoinRecuperadas;
EXECUTE dropTablaExtraJoinConsumos;
EXECUTE dropTablaExtraJoinRecuperadas;
EXECUTE dropTmpDifCon;
EXECUTE dropTmpDifRec;
RAISE NOTICE ' CREATES';
EXECUTE creoTablaJoinConsumos;
EXECUTE creoTablaExtraJoinConsumos;
EXECUTE creoTablaJoinRecuperadas;
EXECUTE creoTablaExtraJoinRecuperadas;
EXECUTE creoTmpDifCon;
EXECUTE creoTmpDifRec;
FOR ultimaFecha IN EXECUTE selectLastEnergiasVehicleData LOOP
RAISE NOTICE ' 122';
--------------------------------------------------------------------------------
--fechas son NULL
--------------------------------------------------------------------------------
--EXECUTE FORMAT('UPDATE %I.%I set (lastenergiacon, lastenergiarec) VALUES = (0, 0);', schemaName, tableName);
--CASE 1 -> compruebo energias consumidas
RAISE NOTICE ' 128';
CASE
WHEN ultimaFecha.lastenergiacon IS NULL THEN
RAISE NOTICE 'CASE 1.1 - LASTENERGIACON ES NULL';
FOR registros IN EXECUTE selectEcon LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, consumo) VALUES (%L, %L, %L, %L);', tablaJoinConsumos, registros.halt, registros.tripid, registros.seq, registros.energiacon);
END LOOP;
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_consumo) SELECT halt, tripid, seq, consumo - LAG(consumo) OVER (ORDER BY consumo) AS dif_consumo FROM %I;', tablaExtraJoinConsumos, tablaJoinConsumos);
--datos de consumida y consumida en modo eco en la misma tabla
FOR registros IN EXECUTE selectExtraJoinConsumos LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_con) VALUES (%L, %L, %L, %L);', tmpDifCon, registros.halt, registros.tripid, registros.seq, registros.dif_consumo);
END LOOP;
EXECUTE FORMAT('UPDATE %I.%I AS a SET dif_energiacon=b.dif_con FROM (SELECT halt, dif_con FROM %I) AS b WHERE a.halt=b.halt;', schemaName, tableName, tmpDifCon);
EXECUTE updateVehicleDataCon;
--------------------------------------------------------------------------------
WHEN ultimaFecha.lastenergiacon IS NOT NULL THEN
RAISE NOTICE 'CASE 1.2 - LASTENERGIACON NO ES NULL';
FOR registros IN EXECUTE FORMAT('SELECT tripid, halt, seq, energiacon FROM %I.%I WHERE seq > 0 AND energiacon > 0 AND halt >= %L ORDER BY halt, energiacon;', schemaName, tableName, ultimaFecha.lastenergiacon) LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, consumo) VALUES (%L, %L, %L, %L);', tablaJoinConsumos, registros.halt, registros.tripid, registros.seq, registros.energiacon);
END LOOP;
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_consumo) SELECT halt, tripid, seq, consumo - LAG(consumo) OVER (ORDER BY consumo) AS dif_consumo FROM %I;', tablaExtraJoinConsumos, tablaJoinConsumos);
--datos de consumida y consumida en modo eco en la misma tabla
FOR registros IN EXECUTE selectExtraJoinConsumos LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_con) VALUES (%L, %L, %L, %L);', tmpDifCon, registros.halt, registros.tripid, registros.seq, registros.dif_consumo);
END LOOP;
--actualizo tabla subtrip y vehicle_data
EXECUTE FORMAT('UPDATE %I.%I AS a SET dif_energiacon=b.dif_con FROM (SELECT halt, dif_con FROM %I) AS b WHERE a.halt=b.halt;', schemaName, tableName, tmpDifCon);
EXECUTE updateVehicleDataCon;
END CASE;
--CASE 2 -> compruebo energias recuperadas
CASE
WHEN ultimaFecha.lastenergiarec IS NULL THEN
RAISE NOTICE 'CASE 2.1 - LASTENERGIAREC ES NULL';
FOR registros IN EXECUTE selectErec LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, recuperada) VALUES (%L, %L, %L, %L);', tablaJoinRecuperadas, registros.halt, registros.tripid, registros.seq, registros.energiarec);
END LOOP;
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_recuperada) SELECT halt, tripid, seq, recuperada - LAG(recuperada) OVER (ORDER BY recuperada) AS dif_recuperada FROM %I;', tablaExtraJoinRecuperadas, tablaJoinRecuperadas);
--datos de energia recuperada y recuperada en modo eco en la misma tabla
FOR registros IN EXECUTE selectExtraJoinRecuperadas LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_rec) VALUES (%L, %L, %L, %L);', tmpDifRec, registros.halt, registros.tripid, registros.seq, registros.dif_recuperada);
END LOOP;
--actualizo tabla subtrip y vehicle_data
EXECUTE FORMAT('UPDATE %I.%I AS a SET dif_energiarec=b.dif_rec FROM (SELECT halt, dif_rec FROM %I) AS b WHERE a.halt=b.halt;', schemaName, tableName, tmpDifRec);
EXECUTE updateVehicleDataRec;
--------------------------------------------------------------------------------
WHEN ultimaFecha.lastenergiarec IS NOT NULL THEN
RAISE NOTICE 'CASE 2.3 - LASTENERGIAREC NO ES NULL';
FOR registros IN EXECUTE FORMAT('SELECT tripid, halt, seq, energiarec FROM %I.%I WHERE seq > 0 AND energiarec > 0 AND halt >= %L ORDER BY halt, energiarec', schemaName, tableName, ultimaFecha.lastenergiarec) LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, recuperada) VALUES (%L, %L, %L, %L);', tablaJoinRecuperadas, registros.halt, registros.tripid, registros.seq, registros.energiarec);
END LOOP;
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_recuperada) SELECT halt, tripid, seq, recuperada - LAG(recuperada) OVER (ORDER BY recuperada) AS dif_recuperada FROM %I;', tablaExtraJoinRecuperadas, tablaJoinRecuperadas);
--datos de energia recuperada y recuperada en modo eco en la misma tabla
FOR registros IN EXECUTE selectExtraJoinRecuperadas LOOP
EXECUTE FORMAT('INSERT INTO %I (halt, tripid, seq, dif_rec) VALUES (%L, %L, %L, %L);', tmpDifRec, registros.halt, registros.tripid, registros.seq, registros.dif_recuperada);
END LOOP;
--actualizo tabla subtrip y vehicle_data
EXECUTE FORMAT('UPDATE %I.%I AS a SET dif_energiarec=b.dif_rec FROM (SELECT halt, dif_rec FROM %I) AS b WHERE a.halt=b.halt;', schemaName, tableName, tmpDifRec);
EXECUTE updateVehicleDataRec;
END CASE;
END LOOP;
------------------------------------------------------------------------------------------------------------------------------------------------------------
RETURN 1;
--------------------------------------------------------------------------------
-- Gestion de excepciones
--------------------------------------------------------------------------------
EXCEPTION WHEN others THEN
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
RAISE NOTICE 'fnc_calcEnergias: %', text_var1;
RAISE NOTICE 'fnc_calcEnergias: %', text_var1;
RAISE NOTICE 'fnc_calcEnergias: %', text_var1;
RETURN 0;
END;
Следующее изображение показывает проблему, 4-й столбец - это потребление электроэнергии, а 5-й столбец - это разница между потреблением, что я пытаюсьобъяснить.(То же самое происходит с 6-м и 7-м столбцами, это восстановленная энергия).
Это то, что я получаю
Как это могло бытьсделанный?Одним из вариантов может быть полное обновление без сохранения даты последнего обновления, но я предпочитаю по возможности избегать этого.
Заранее спасибо!