Как заменить значения NULL с помощью оконной функции LAG при обновлении таблицы? - PullRequest
0 голосов
/ 31 мая 2019

У меня есть база данных 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-м столбцами, это восстановленная энергия).

Это то, что я получаю

Как это могло бытьсделанный?Одним из вариантов может быть полное обновление без сохранения даты последнего обновления, но я предпочитаю по возможности избегать этого.

Заранее спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...