I'm using PostgreSQL v10.12
Table 1: Threshold with total rows ~800
(Each sensor's minimum and maximum threshold level is store in this table)
Description:
SensorName Varchar(10),
MinLimit numeric,
MaxLimit numeric
Data:
SensorName | MinLimit | MaxLimit
Sensor1 | 80 | 115
Sensor2 | 60 | 70
Sensor3 | 100 | 120
...
Sensor800 | 60 | 70
Table 2: IoTData with total columns ~800+
(Each sensor in Threshold table is the column in IoTData table)
Description:
IoTDateTime timestamp without time zone,
sensor1 numeric(3)
sensor2 numeric(8,5)
sensor3 numeric(5,2)
....
Sensor800 numeric(5,2)
For every 5 minutes record will be generated in this table. This table is partitioned with date range (4 months data will be in a partition). Likewise there are 6 partitions in for this table so far.
*e.g:
IoTDateTime | Sensor1
2020-01-01 11:05:00 | 85
2020-01-01 11:10:00 | 80
2020-01-01 11:15:00 | 77
...
2020-01-31 23:50:00 | 70
2020-01-31 23:55:00 | 70
From Table 1 Threshold
this Sensor1
's MinLimit
is 80
and MaxLimit
is 115
. Anything below MinLimit
(80
) or greater than MaxLimit
(115
) is considered as alert or sensor is malfunctioning.
I need to find the alert count of all 800+ sensors for each day of a month.
I wrote below function to perform this logic.
Need your help to rewrite this function in better way to reduce the line of code and optimistic logic. Thanks in advance :)
CREATE OR REPLACE FUNCTION public.udf_SensorFailedForeachDay
( pimono integer,
pstartdate timestamp without time zone,
penddate timestamp without time zone)
RETURNS TABLE(date_of_month double precision, Sensor1 double precision, Sensor2 double precision,
...
, Sensor800 double precision)
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
declare Sensor1min numeric(3);declare Sensor1max numeric(3);
declare Sensor2min numeric(8,5);declare Sensor2max numeric(8,5);
....
declare Sensor800min numeric(5,2);declare Sensor800max numeric(5,2);
BEGIN
select minlimit,maxlimit Into Sensor1min,Sensor1max from threshold where channelname='Sensor1';
select minlimit,maxlimit Into Sensor2min,Sensor2max from threshold where channelname='Sensor2';
...
select minlimit,maxlimit Into Sensor800min,Sensor800max from threshold where channelname='Sensor800';
Return query
select extract(day from a.IoTDateTime) as date_of_month,
(cast(sum(case when a.Sensor1 between Sensor1min and Sensor1max then 1 end) as float)/cast(count(a.IoTDateTime) as float) )*100 as Sensor1,
(cast(sum(case when a.Sensor2 between Sensor2min and Sensor2max then 1 end) as float)/cast(count(a.IoTDateTime) as float))*100 as Sensor2,
...
(cast(sum(case when a.Sensor800 between Sensor800min and Sensor800max then 1 end) as float)/cast(count(a.IoTDateTime) as float))*100 as Sensor800
from IoTData a where a.IoTDateTime between Pstartdate and Penddate
group by extract(day from a.IoTDateTime) order by extract(day from a.IoTDateTime);
END;
$BODY$;