Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with:

Problems With Storing Date And Time Separately In SQL Server

By Ben Nadel on
Tags: SQL

I just added links for previous and next blog posts at the bottom of every blog entry detail page. I stumbled a bit when trying to query for the previous and next posts because of the way I store the date and time of posting in the database. Over time I have learned it is easier to store date and time separately where date is in a DATETIME field (with zero time) and the time is stored as 24 hour time in a VARCHAR(5) field (ex. 17:15). This makes manipulation and date comparison easy... most of the time.

In this case, however, it did cause a slight problem. Having already queried for the detail blog post, my initial query went something like this (for shorter code, assume that @id is the current entry ID and that @date_posted is the current entry's date of posting):

  • <!--- Query for next post. --->
  • <cfquery name="REQUEST.NextQuery" datasource="..." username="..." password="...">
  • SELECT TOP 1
  • b.id,
  • b.name,
  • b.date_posted,
  • b.time_posted
  • FROM
  • blog_entry b
  • WHERE
  • <!--- Exclude the current entry. --->
  • b.id != @id
  • AND
  • <!--- Get only newish entries. --->
  • b.date_posted >= @date_posted
  • ORDER BY
  • b.date_posted ASC,
  • b.time_posted ASC
  • </cfquery>
  •  
  •  
  • <!--- Query for prev post. --->
  • <cfquery name="REQUEST.PrevQuery" datasource="..." username="..." password="...">
  • SELECT TOP 1
  • b.id,
  • b.name,
  • b.date_posted,
  • b.time_posted
  • FROM
  • blog_entry b
  • WHERE
  • <!--- Exclude the current entry. --->
  • b.id != @id
  • AND
  • <!--- Get only oldish entries. --->
  • b.date_posted <= @date_posted
  • ORDER BY
  • b.date_posted DESC,
  • b.time_posted DESC
  • </cfquery>

This worked most of the time so the problem wasn't immediately apparent. Sometimes though, the previous and next entries were the same link. After doing some CFDump'ing, I realized that the time_posted field was causing issues, or rather, the fact that it was stored separately was causing issues.

Take for example the three posts:

A. 7/27/2006 - 10:00 AM
B. 7/27/2006 - 09:00 AM
C. 7/26/2006 - 12:00 PM

Now, let's assume that post (B) is the current post. If I were to query for the next and previous posts based only on the date field (as the queries above do), I would get post (A) for both the previous and next results since date equality is allowed. After that, sorting on the time posted is moot as the data is already invalid.

To overcome this, I had to start taking the time into account in the WHERE clause, not just in the ORDER BY. The result is a little hacky, but seems to do the trick (for shorter code, assume that @id is the current entry ID, that @date_posted is the current entry's date of posting, and that @time_posted is the current entry's time of posting):

  • <!--- Query for the next post. --->
  • <cfquery name="REQUEST.NextQuery" datasource="..." username="..." password="...">
  • SELECT TOP 1
  • b.id,
  • b.name,
  • b.date_posted,
  • b.time_posted
  • FROM
  • blog_entry b
  • WHERE
  • <!--- Exclude the current entry. --->
  • b.id != @id
  • AND
  • <!--- Get only newish entries. --->
  • b.date_posted >= @date_posted
  • <!---
  • We have to fudge it a bit here to take the time of
  • posting into account.
  • --->
  • AND
  • (
  • <!---
  • We only need to take the time of posting into account
  • if we are looking at the date of the current post.
  • Otherwise, time of posting is irrelevant.
  • --->
  • CASE
  • WHEN
  • b.date_posted = @date_posted
  • THEN
  • CASE
  • WHEN
  • b.time_posted >= @time_posted
  • THEN
  • 1
  • ELSE
  • 0
  • END
  • ELSE
  • 1
  • END
  • ) = 1
  • ORDER BY
  • b.date_posted ASC,
  • b.time_posted ASC
  • </cfquery>
  •  
  •  
  • <!--- Query for the previous post. --->
  • <cfquery name="REQUEST.PrevQuery" datasource="..." username="..." password="...">
  • SELECT TOP 1
  • b.id,
  • b.name,
  • b.date_posted,
  • b.time_posted
  • FROM
  • blog_entry b
  • WHERE
  • <!--- Exclude the current entry. --->
  • b.id != @id
  • AND
  • <!--- Get only oldish entries. --->
  • b.date_posted <= @date_posted
  • <!---
  • We have to fudge it a bit here to take the time of
  • posting into account.
  • --->
  • AND
  • (
  • <!---
  • We only need to take the time of posting into account
  • if we are looking at the date of the current post.
  • Otherwise, time of posting is irrelevant.
  • --->
  • CASE
  • WHEN
  • b.date_posted = @date_posted
  • THEN
  • CASE
  • WHEN
  • b.time_posted <= @time_posted
  • THEN
  • 1
  • ELSE
  • 0
  • END
  • ELSE
  • 1
  • END
  • ) = 1
  • ORDER BY
  • b.date_posted DESC,
  • b.time_posted DESC
  • </cfquery>

As you can see above, I now have to take both date and time into account when doing the comparison (not just the sorting) since they are stored separately. However, time is not always relevant; if the entries were posted on different days, I only care about the time posted when sorting, not elimination. I only have to take time into account for entries posted on the same day. Not the end of the world, but it makes for a less elegant query. I still think that in the long run, storing date and time separately has many more benefits than draw backs.



Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.