Сравните дату и секунды с отметкой времени - PullRequest
0 голосов
/ 27 мая 2020

У меня есть таблица Postgres, в которой хранится созданная метка времени в столбце created_date DATE, и столбец created_time INT, содержащий секунды с полуночи.

EDIT : Таблица находится в производственная база данных клиента и хранит данные из более старой системы, изменить схему невозможно.

Я хотел бы сделать выбор на основе созданной временной метки.

В MySQL Я бы написал :

SELECT * FROM MyCustomers
WHERE ADDTIME(created_date,SEC_TO_TIME(created_time)) > 'sometimestampliteral'

Как это будет выглядеть в PostgreSQL?

Я вижу примеры в руководстве, но все они используют буквальные значения, а не значения из столбцов таблицы.

Ответы [ 3 ]

2 голосов
/ 27 мая 2020

Вы можете использовать make_interval(), чтобы превратить секунды в интервал, который, в свою очередь, можно добавить в столбец date для построения правильного timestamp:

created_date + make_interval(secs => created_time)
1 голос
/ 27 мая 2020

Просто сложите два вместе:

created_date + created_time * interval '1 second' > ?
0 голосов
/ 28 мая 2020

Придерживаясь вашего дизайна

Предполагается формат ISO для 'somedateliteral'.
Поскольку это должен быть литерал временной метки, я назову его 'timestamp_literal'.

SELECT *, created_date + make_interval(secs => created_time) AS created_at
FROM   mycustomers
WHERE  (created_date, created_time)
     > (date 'timestamp_literal', EXTRACT(epoch FROM time 'timestamp_literal')::int);

date 'timestamp_literal' и time 'timestamp_literal' берут соответствующую часть даты / времени из литерала. (Последний прерывается, если нет временной части, тогда как первый, очевидно, работает и с литералом даты.)

Почему?

Чтобы сделать его «саргируемым». См .:

В отличие от решений, вычисляющих метку времени на лету ¹, этот запрос может используйте базовый c многоколоночный индекс :

CREATE INDEX multicolumn_created ON mycustomers (created_date, created_time);

(¹ Вы могли бы создать соответствующий индекс выражения, чтобы он работал. ..)

Postgres может идеально использовать этот индекс с сравнение значений ROW . (В прошлый раз, когда я посмотрел, MySQL не смог этого сделать.) См.:

Правильное исправление

Обычно временные метки хранятся как date + integer это ошибка дизайна без преимуществ. Вместо этого используйте timestamp. Вы можете переключиться на обычно предпочитаемый timestamptz, находясь на нем. См .:

В других ответах уже предоставлены выражения для преобразования (date, integer) в timestamp - который вы можете использовать для исправления вашей таблицы:

BEGIN;

-- drop all depending objects: indexes, views, ...

ALTER TABLE mycustomers
   ALTER created_date TYPE timestamp
      USING (created_date + make_interval(secs => created_time)) 
 , DROP COLUMN created_time;

ALTER TABLE mycustomers RENAME created_date TO created_at;  -- or whatever

-- recreate all depending objects: indexes, views, ...

COMMIT;

Очевидно, принять все запросы с использованием этих столбцов. Запрос просто выглядит следующим образом:

SELECT * FROM mycustomers WHERE created_at > 'somedateliteral';

db <> fiddle здесь

...