简体   繁体   中英

“malformed array literal” error in PL/pgSQL

I got an error in PL/pgSQL :

"ERROR: malformed array literal: "2019-11-22 09:18:07.248537" DETAIL: Array value must start with "{" or dimension information. CONTEXT: PL/pgSQL function chargelengtth() line 11 at FOR over SELECT rows"

CREATE OR REPLACE FUNCTION chargelengtth() RETURNS text AS
$$
DECLARE chargetime integer;
DECLARE othertime integer;
DECLARE total integer;
DECLARE charge_length text[];
DECLARE chargestatus text;
DECLARE otherstatus text;
BEGIN
    total := 0;
    chargetime := 0;
FOR charge_length IN
    SELECT * FROM table_name
LOOP
    RAISE NOTICE 'Stuff: %', charge_length;
    IF(charge_length[diagnostic] = 'Charging' AND chargetime = 0) THEN
        chargetime := extract(epoch from charge_length[time]);
    END IF;

    IF(charge_length[diagnostic] != 'Charging') THEN
        othertime := extract(epoch from charge_length[time]);
        total := total + (othertime - chargetime);
        chargetime := 0;
    END IF;

END LOOP;
RETURN to_char(total * interval '1 sec','HH24h MIm');
END$$ LANGUAGE plpgsql;
SELECT * FROM chargelengtth()`

can you please share your knowledge to resolve this issue.

As documented in the manual you need to use a record variable when you want to loop over a SELECT statement:

CREATE OR REPLACE FUNCTION chargelengtth() 
  RETURNS text AS
$$
DECLARE 
  chargetime integer;
  othertime integer;
  total integer;
  chargestatus text;
  otherstatus text;
  l_row record; --<< here
BEGIN
  total := 0;
  chargetime := 0;
  FOR l_row IN SELECT * FROM table_name
  LOOP
      RAISE NOTICE 'Stuff: %', l_row;
      IF (l_row.diagnostic = 'Charging' AND chargetime = 0) THEN
          chargetime := extract(epoch from l_row.time);
      END IF;

      IF (l_row.diagnostic != 'Charging') THEN
          othertime := extract(epoch from l_row.time);
          total := total + (othertime - chargetime);
          chargetime := 0;
      END IF;

  END LOOP;
  RETURN to_char(total * interval '1 sec','HH24h MIm');
END$$ LANGUAGE plpgsql;

SELECT chargelengtth()

As far as I can tell, you can replace this with a single SELECT statement. Assuming the time column is a timestamp , I think the following is equivalent to what you are doing (except for the formatting of the interval at the end):

with ct (chargetime) as (
  select time 
  from table_name
  where diagnostic = 'Charging'
  limit 1
)
select sum(t.time - ct.chargetime) 
from the_table t
  cross join ct
where t.diagnostic <> 'Charging'

The retrieval of the chargetime is a bit confusing as you seem to rely on some order of the rows, yet your query has no order by . The limit 1 without an order by does essentially the same, but if you want reproducible results you should really specify an order by (also for your FOR loop statement)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM