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.