My question is supported by this dbfiddle demo.
I have a table defined like so:
CREATE TABLE status_table
(
base_name text NOT NULL
, version smallint NOT NULL
, ref_time int NOT NULL
, processed bool NOT NULL
, processing bool NOT NULL
, updated int NOT NULL DEFAULT (extract(epoch from now()) / 60)
, PRIMARY KEY (base_name, version)
);
And a SELECT
query as follows:
SELECT
ref_time
, MAX(updated) AS max_updated
, COUNT(*) AS total
, COUNT(*) FILTER (WHERE processed) AS proc
, ROUND(COUNT(*) FILTER (WHERE processed) * 100.0 / COUNT(*), 1) AS percent
, ROUND(ROUND(COUNT(*) FILTER (WHERE processed) * 1.0 / COUNT(*), 1) * 100) AS rounded
, COUNT(*) FILTER (WHERE processed) = COUNT(*) AS complete
, MAX(updated) < (ROUND(EXTRACT(epoch from now()) / 60) - 200) AS settled
, (COUNT(*) FILTER (WHERE processed) = COUNT(*)) AND (MAX(updated) < (ROUND(EXTRACT(epoch from now()) / 60) - 200)) AS ready
FROM
status_table
GROUP BY
ref_time
ORDER BY
ready DESC, rounded DESC, ref_time DESC
There is a lot of repetition in the above query, with certain expressions (e.g. count(*) FILTER (WHERE processed)
) appearing in more than one place. I understand that, when this query is run, it is optimised automatically so that it doesn't matter from a performance point of view, i.e. each common expression is evaluated only once even if it appears more than once.
However, from a readability point of view, I would really like something along the following lines, with each repeated expression being defined just once and then re-used:
SELECT ref_time
, max(updated) AS max_updated
, count(*) AS total
, count(*) FILTER (WHERE processed) AS proc
, round(proc * 100.0 / total, 1) AS percent
, round(round(proc * 1.0 / total, 1) * 100) AS rounded
, processed = total AS complete
, round(extract(epoch from now()) / 60) AS now_mins
, 200 AS interval_mins
, max_updated < now_mins - interval_mins AS settled
, complete AND settled AS ready
FROM status_table
GROUP BY ref_time
ORDER BY ready DESC, rounded DESC, ref_time DESC
Of course, this throws an error column "proc" does not exist
, so it's clearly not possible. But what is the nearest equivalent of the above layout? I had a go with Common Table Expressions, defining the common expressions in one CTE and trying to refer back to them in the next, but got in a complete muddle, partly due to the presence GROUP BY
I think... and I soon got the feeling that it would be more verbose and less readable despite my valiant attempts.
Is there a way to achieve better readability of the query in this context?