0

I have a table which looks like this:

Table t1

timestamp (pkey)     | A  | B | C
----------------------------------
2024-01-01 12:00:00  | 1  | 2 | 2
2024-01-01 12:00:01  | 1  | 2 | 2
2024-01-01 12:00:03  | 15 | 4 | 2

Table creation SQL:

CREATE TABLE IF NOT EXISTS t1 ("id" serial NOT NULL, "timestamp" timestamp PRIMARY KEY, "A" real, "B" real, "C" real)

Some tables might have 100+ columns.

I'd like to select several columns having omitting time ranges on per column basis. The way I do it today is like the following:

SELECT 
(CASE WHEN timestamp NOT BETWEEN '2017-06-12T17:01' AND '2018-06-12T21:57'
                    AND timestamp NOT BETWEEN '2020-06-12T17:01' AND '2021-02-15T21:57' THEN A ELSE NULL END) "A",

(CASE WHEN timestamp NOT BETWEEN '2018-07-14' AND '2019-01-01'
                    AND timestamp NOT BETWEEN '2020-06-12T17:01' AND '2021-02-15T21:57' THEN B ELSE NULL END) "B",

C
FROM t1
WHERE timestamp > '2014-01-01'

timestamp is an index obviously.

Is there a better / more effective way to do it?

7
  • no, but what says EXPLAIN and ANALAYSE
    – nbk
    Commented Mar 25 at 20:56
  • 2
    Sounds like you need to normalize your table into rows. Commented Mar 25 at 22:17
  • 1
    The index will help with the WHERE condition, but it cannot help with the CASE, nor is there a need to speed up the CASE. This smells as if there could be a better data model. Commented Mar 26 at 7:15
  • 1
    Hi, and welcome to dba.se! Please show us the DDL for the table concerned - you can give us a shortened version - as per your example above. Also, as an aside, it is not a good idea to use SQL and/or PostgreSQL keywords as identifiers - i.e. column, table, index... whatever names. See the list here for identifiers to be avoided - it makes debugging difficult and your system less portable.
    – Vérace
    Commented Mar 26 at 11:24
  • @LaurenzAlbe - I was suggested many times to change the data model. But think of it this way - I sometimes have 600 columns of data, with millions of rows. The data is usually aligned to timestamps. Putting all the data in TIMESTAMP-NAME-VALUE structure (which is usually the recommendation) has a horrible performance when you need to select multiple columns or JOIN it with other similarly structured tables.
    – Miro
    Commented Mar 26 at 14:33

1 Answer 1

0

Don't use BETWEEN for timestamps.
I also inverted the logic in the CASE expression to simplify, and to not exclude values for timestamp IS NULL (which may or may not be allowed).

SELECT CASE WHEN timestamp >= '2017-06-12T17:01' AND timestamp < '2018-06-12T21:58'
              OR timestamp >= '2020-06-12T17:01' AND timestamp < '2021-02-15T21:58' THEN null ELSE a END AS a
     , CASE WHEN timestamp >= '2018-07-14'       AND timestamp < '2019-01-02'
              OR timestamp >= '2020-06-12T17:01' AND timestamp < '2021-02-15T21:58' THEN null ELSE b END AS b
     , c
FROM   t1
WHERE  timestamp > '2014-01-01';

We don't need parentheses. Operator precedence works in our favor in either query.

2
  • that's an interesting observation. But will it improve the performance also?
    – Miro
    Commented Mar 27 at 15:13
  • @Miro: Barely. The CASE expressions cost close to nothing. The WHERE clause drives the cost. Looks like you are selecting many rows. Commented Mar 27 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.