steevithak
steevithak

Reputation: 965

PostgreSQL: How to use char column containing a timestamp

I'm working with a PostgreSQL database that includes a char column containing textual timestamps in the format "Prefix: Wed May 7, 11:30AM-1:30PM". There are no years, all dates are assumed to be within the current year. I realize it would be easier to work with this data if it were in columns with a type of timestamp or date and time but I do not have any control over the database format, I have to work with what's there.

What I need to do is write a SELECT that returns only records with a specific prefix value (e.g. "public" vs "private") AND a time/date equal to later than the current time/date. This is a relatively large database with around 100,000 records and I need to be able to do the search quickly. Can anyone offer advice on the best way to achieve this? I've considered using a regex or a combination of to_date() and substring() but I'm uncertain how to proceed.

Bonus question: is there a way to Order the records sequentially by date and time using this field?

Upvotes: 1

Views: 362

Answers (2)

jed
jed

Reputation: 615

If you need to be able to use the dates as a range, you can use Postgres range capabilities. (Or you could of course just set up start and end dates. Both are done in the example below.)

WITH initial_strings AS (
SELECT 'Public: Wed May 7, 11:30AM-1:30PM'::varchar as char_time),

split_up AS
(
SELECT
split_part(char_time, ':', 1) prefix,
split_part(split_part(char_time,',',2), '-', 1)::TIME start_time,
split_part(split_part(char_time,',',2), '-', 2)::TIME end_time,
to_timestamp(to_char(now(), 'YYYY') || 
            split_part(split_part(char_time,',',1), ':', 2),
            'YYYY Dy Mon dd'
            ) as the_day
FROM initial_strings),

new_format AS
(
SELECT 
prefix,
tstzrange((the_day + start_time),(the_day + end_time)) time_range,
the_day + start_time started_at,
the_day + end_time ended_at
FROM split_up
ORDER BY started_at) --Performs the required ordering

SELECT *
FROM new_format
WHERE prefix = 'Public'
AND started_at >= '2014-05-07';

This of course assumes that your times are always within the same day. If thats not the case, you'll have to be a little bit trickier with your splitting, but it should just be a slight modificaion of this.

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1270643

I think something like this will work:

select split_part(col, ':', 1) as prefix,
       to_timestamp(to_char(now(), 'YYYY') || 
                    split_part(col, ':', 2),
                    'YYYY Dy Mon dd, HH:MIAM'
                   ) as DateTime

Upvotes: 3

Related Questions