I have a date and a time field in Postgresql. I am reading it in python and need to sort out things on certain days past certain times.
The steps would basically be like this:
- Select * from x where date > monthdayyear
- In that subset, select only those that are > time given for that date
- AND date2 must be < monthdayyear2 AND time2 must be less than time2 given on that date
I know there are definitely some python ways I could do this, by iterating through results and et cetera. I’m wondering if there is a better way than brute forcing this? I would rather not run multiple queries or have to sort out a lot of extra results in the fetchall() if possible.
If I’ve understood your design, this is really a schema design issue. Instead of:
you generally want:
if you want the timestamp converted automatically to UTC and back to the client’s
TimeZone, ortimestamp without time zoneif you want to store the raw timestamp without timezone conversion.If an inclusive test is OK, you can write:
If you cannot amend your schema, your best bet is something like this:
This may have some unexpected quirks when it comes to clients in multiple time zones; you may land up needing to look at the
AT TIME ZONEoperator.If you need an exclusive test on one side an/or the other, you can’t use
BETWEENsince it’s ana <= x <= boperator. Instead write:Automating the schema change
Automating a schema change is possible.
You want to query
INFORMATION_SCHEMAorpg_catalog.pg_classandpg_catalog.pg_attributefor tables that have pairs ofdateandtimecolumns, then generate sets ofALTER TABLEcommands to unify them.Determining what a “pair” is is quite application specific; if you’ve used a consistent naming scheme it should be easy to do with
LIKEor~operators and/orregexp_matches. You want to produce a set of(tablename, datecolumnname, timecolumnname)tuples.Once you have that, you can for each
(tablename, datecolumnname, timecolumnname)tuple produce the followingALTER TABLEstatements, which must be run in a transaction to be safe, and should be tested before use on any data you care about, and where the entries in[brackets]are substitutions:then check the results and
COMMITif happy. Be aware that an exclusive lock is taken on the table from the firstALTERso nothing else can use the table until youCOMMITorROLLBACK.If you’re on a vaguely modern PostgreSQL you can generate the SQL with the
formatfunction; on older versions you can use string concatenation (||) and thequote_literalfunction. Example:Given the sample data:
Here’s a query that generates the input data set. Note that it relies on the naming convention that matching column pairs always have a common name once any
dateortimeword is removed from the column. You could instead use adjacency by testing forc1.attnum + 1 = c2.attnum.You can read the results and send them as SQL commands in a second session, or if you want to get fancy you can write a fairly simple PL/PgSQL function that
LOOPs over the results andEXECUTEs each one. The query produces output like:I don’t know if there’s any useful way to work out on a per-column basis whether you want
WITH TIME ZONEorWITHOUT TIME ZONE. It’s likely you’ll land up just doing it hardcoded, in which case you can just remove that column. I put it in there in case there’s a good way to figure it out in your application.If you have cases where the time can be null but the date non-null or vice versa, you will need to wrap the date and time in an expression that decide what result to return when null. The
nullifandcoalescefunctions are useful for this, as isCASE. Remember that adding a null and a non-null value produces a null result so you may not need to do anything special.If you use schemas you may need to further refine the query to use %I substitution of schema name prefixes to disambiguate. If you don’t use schemas (if you don’t know what one is, you don’t) then this doesn’t matter.
Consider adding
CHECKconstraints enforcing thattime1is less than or equal totime2where it makes sense in your application once you’ve done this. Also look at exclusion constraints in the documentation.