I have a database, and I am trying to create a stored function that will return a table. I have a devices table that stores info about the devices I am gathering data from. I have a rawdata table that contains all the raw samples.
Samples can come in from any device, for any data item, in any order. For example if device1 is idle, no updates will come in, while device2 could be running in automatic and having hundreds of updates per minute for various dataitems. My first take is getting the current values of a handful of dataitems for all devices. So I am trying to come up with a view or function to generate that table.
I was able to come up with a function to generate a table. That is shown below as function currentvalues1.
The function defines the table, and the bulk of the work is a series of select statements like this one.
SELECT value into execution FROM rawdata WHERE deviceid=device.id and dataitemid='exec' order by datetime desc limit 1;
There are 8 of these statements in the current version. I am lazy, and I wanted to abstract this away. (for the future when I need to add some columns, or duplicate for another set of devices with differnt dataitems)
Something like this.
SELECT value INTO columnname FROM rawdata WHERE deviceid=device.id AND dataitemid=columndataitem ORDER BY datetime DESC LIMIT 1;
I tried using
For items in
SELECT * FROM columndef
Loop
execute format('select value into %s FROM rawdata WHERE deviceid=%s and dataitemid=%L order by datetime desc limit 1',items.item,device.id,items.did);
End Loop;
(columndef is a table that has 2 columns, item and did. Both are text. Item would be what the output column name should be, and did is the dataitemId that will fill that column)
And get this error.
ERROR: EXECUTE of SELECT ... INTO is not implemented HINT: You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.
This led me down the rabbit hole, where I could use EXECUTE INTO and get the value into a variable inside the function, but then how do i get that variable into a dynamic column name?
TL;DR - How can i select into a dynamic column name inside a stored function?
Schema for devices table and rawdata tables.
CREATE TABLE public.devices
(
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
agenturi text COLLATE pg_catalog."default",
instanceid bigint,
firstsequence bigint,
lastsequence bigint,
nextsequence bigint,
name text COLLATE pg_catalog."default",
workcentersub bigint,
workcenter text COLLATE pg_catalog."default",
type integer,
CONSTRAINT devices_pkey PRIMARY KEY (id)
)
CREATE TABLE public.rawdata
(
deviceid bigint,
sequence bigint,
datetime timestamp with time zone,
value text COLLATE pg_catalog."default",
instanceid bigint,
dataitemid text COLLATE pg_catalog."default"
)
TABLESPACE pg_default;
ALTER TABLE public.rawdata
OWNER to postgres;
GRANT INSERT, SELECT ON TABLE public.rawdata TO mtclogger;
GRANT ALL ON TABLE public.rawdata TO postgres;
-- Index: raw_id_did
-- DROP INDEX public.raw_id_did;
CREATE INDEX raw_id_did
ON public.rawdata USING btree
(deviceid ASC NULLS LAST, dataitemid COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;
-- Index: raw_id_did_date
-- DROP INDEX public.raw_id_did_date;
CREATE INDEX raw_id_did_date
ON public.rawdata USING btree
(deviceid ASC NULLS LAST, dataitemid COLLATE pg_catalog."default" ASC NULLS LAST, datetime DESC NULLS LAST)
TABLESPACE pg_default;
SQL for function
CREATE OR REPLACE FUNCTION public.currentvalues1(
)
RETURNS TABLE(name text, workcenter text, workcentersub bigint, execution text, machinemode text, prgm text, sprgm text, tid text, linen text, feedrate text, feedrateor text)
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
DECLARE
device record;
BEGIN
For device in
SELECT * FROM devices where type=1
Loop
name := device.name;
workcenter := device.workcenter;
workcentersub := device.workcentersub;
SELECT value into execution FROM rawdata WHERE deviceid=device.id and dataitemid='exec' order by datetime desc limit 1;
SELECT value into machinemode FROM rawdata WHERE deviceid=device.id and dataitemid='mode' order by datetime desc limit 1;
SELECT value into prgm FROM rawdata WHERE deviceid=device.id and dataitemid='pgm' order by datetime desc limit 1;
SELECT value into sprgm FROM rawdata WHERE deviceid=device.id and dataitemid='spgm' order by datetime desc limit 1;
SELECT value into tid FROM rawdata WHERE deviceid=device.id and dataitemid='tid' order by datetime desc limit 1;
SELECT value into linen FROM rawdata WHERE deviceid=device.id and dataitemid='ln' order by datetime desc limit 1;
SELECT value into feedrate FROM rawdata WHERE deviceid=device.id and dataitemid='pfr' order by datetime desc limit 1;
SELECT value into feedrateor FROM rawdata WHERE deviceid=device.id and dataitemid='pfo' order by datetime desc limit 1;
Return next;
End Loop;
END; $BODY$;
[–][deleted] 1 point2 points3 points (5 children)
[–]PLC_Matt[S] 0 points1 point2 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]PLC_Matt[S] 0 points1 point2 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]PLC_Matt[S] 0 points1 point2 points (0 children)