I have the following table in Postgres 9.6:
CREATE TABLE some_tbl(
target_id integer NOT NULL
, machine_id integer NOT NULL
, dateread timestamp without time zone NOT NULL
, state text
, ftime text
, CONSTRAINT pk_sometable PRIMARY KEY (target_id, machine_id, dateread)
);
With data like:
targetID | MachineID | DateRead | State | FTime |
---|---|---|---|---|
60000 | 30 | '2021-09-29 15:20:00' | '0|1|0' | '850|930|32000' |
60000 | 31 | '2021-09-29 16:35:13' | '0|0|0' | '980|1050|30000' |
The important part is state
and ftime
. I need to unnest elements and keep their order. This generates steps.
For example, the first row will be:
targetID | MachineID | DateRead | State | FTime | Step |
---|---|---|---|---|---|
60000 | 30 | '2021-09-29 15:20:00' | '0' | '850' | 0 |
60000 | 30 | '2021-09-29 15:20:00' | '1' | '930' | 1 |
60000 | 30 | '2021-09-29 15:20:00' | '0' | '32000' | 2 |
The ORDER is important, because FTIME 850 ms is always FIRST and gets value 0 in STEP, then later 930 ms is the second and get step 1 and at last 32000 ms is the third and get step 2.
Currently, I resolve this by first using string_to_array()
to transform the text to array, then unnnest()
and finally use row_number()
to assign the step number.
This work fantastically - except sometimes some index appears out of order. Like this for the first row:
targetID | MachineID | DateRead | State | Ftime | Step |
---|---|---|---|---|---|
60000 | 30 | '2021-09-29 15:20:00' | '1' | '930' | 0 |
60000 | 30 | '2021-09-29 15:20:00' | '0' | '32000' | 1 |
60000 | 30 | '2021-09-29 15:20:00' | '0' | '850' | 2 |
I do it over a thousands of records and practically all are ok, but later I must do statistics and need get min, max, average and get wrong values, so I check and i see are the index wrong (I move statistics with a massive ETL process) but if I execute the select checking the specific row with error it show perfect. So I assume than row_number have problems with index some times and this is very random.
This is the SQL that i use:
SELECT foo.target_id,
dateread,
foo.machine_id,
foo.state,
foo.ftime::integer,
(row_number() OVER (PARTITION BY foo.dateread, foo.machine_id, foo.target_id)) - 1 AS step
FROM ( SELECT target_id,
machine_id,
dateread
unnest(string_to_array(state, '|'::text))::integer AS state,
unnest(string_to_array(ftime, '|'::text))::integer AS tiempo
FROM some_table
WHERE target_id IN (6000) AND dateread = '2021-06-09')foo
Is there some better way to do this?