views:

185

answers:

2
+1  Q: 

oracle date range

Hi,

using a Oracle 10g db I have a table something like this:

 create table x(
 ID NUMBER(10) primary key,
 wedding DATE NOT NULL
 );

how can I

 select * from x where wedding is in june 2008???

I know it is probably an easy one but I couldn't find any satisfying answer so far. Help is very much appreciated.

+4  A: 

Use:

SELECT *
  FROM x
 WHERE x.wedding BETWEEN TO_DATE('2008-JUN-01', 'YYYY-MON-DD') 
                            AND TO_DATE('2008-JUL-01', 'YYYY-MON-DD')

Use of TO_DATE constructs a date with a time portion of 00:00:00, which requires the end date to be one day ahead unless you want to use logic to correct the current date to be one second before midnight. Untested:

TO_DATE('2008-JUN-30', 'YYYY-MON-DD') + 1 - (1/(24*60*60))

That should add one day to 30-Jun-2008, and then subtract one second in order to return a final date of 30-Jun-2008 23:59.

References:

OMG Ponies
lol thx so obvious
Hoax
DATE type in ORACLE contains date and time component. Expression TO_DATE('2008-JUN-30', 'YYYY-MON-DD') equals to '2008-JUN-30 00:00:00' . If data contains time information, then you can have problems with this expression. Wedding that happens on '2008-JUN-30 16:00:00' (4pm), won't be in result set of above query.
zendar
so I should set it to BETWEEN 01 of June and 01 of July.
Hoax
Re "Use of TO_DATE ..." - I agree it is a bit more complicated if you have time and date together. Your current upper limit: `TO_DATE('2008-JUL-01', 'YYYY-MON-DD')` now can get weddings from 2008-JUL-01 that don't have time entered (I presume that there are no midnight weddings), so this query can be inaccurate to. You probably need to elaborate edge cases and add some comment on time portion and BETWEEN operator.
zendar
@Hoax - if you don't have time component in `x.wedding`, then first version is fine: `TO_DATE('2008-JUN-30', 'YYYY-MON-DD')`. Else you should set upper limit to `2008-JUN-30 23:59:59`. Check TO_DATE documentation for correct mask.
zendar
@zendar: Oracle defaults the time portion to 00:00:00 if it isn't specified, which I think was your real point. That's why I added the logic for a datetime that is a second before midnight.
OMG Ponies
@zendar: Oracle's DATE data type *includes* **both** date **and** time.
OMG Ponies
@OMG Ponies: you're right :). Sometimes it's hard to me say simple things with few words. Maybe I should reconsider management position I was offered some time ago.
zendar
How about this:`WHERE x.wedding >= TO_DATE('2008-06-01','YYYY-MM-DD') AND x.wedding < ADD_MONTHS(TO_DATE('2008-06-01','YYYY-MM-DD'), 1)` ? This gets rid of the time problem, even deals with leap seconds, and only requires you to enter one unique literal.
Roland Bouman
@Roland: `ADD_MONTHS` is the same as just defining the date to be July 1st. Sidestepping the inclusiveness of `BETWEEN` is the issue, but using `BETWEEN` is preferable because it is a single evaluation. The behavior isn't obvious in this example, you'd have to use random number generation for it to be apparent.
OMG Ponies
What do you mean that `BETWEEN` is a single operation? Sure, it's one operator at the SQL level, but I don't think you can conclude that under the covers that will generate one operation in the executor. In fact, when I do explain plan, I see both statements generate an almost identical plan. The contents of PLAN_TABLE.ACCESS_PREDICATES suggests that BETWEEN is rewritten as column >= date AND column <= date. Or perhaps you meant something else and I am missing it?
Roland Bouman
whether it's one or two "operations" is (almost always) not a significant issue in the context of an execution plan.
Jeffrey Kemp
BTW personally I like this simple formula to get the last second of the day: `TO_DATE('2008-JUL-01','YYYY-MON-DD')-0.00001`
Jeffrey Kemp
A: 

This is ANSI SQL, and supported by oracle as of version 9i

SELECT *
FROM   x
WHERE  EXTRACT(YEAR  FROM wedding) = 2008
AND    EXTRACT(MONTH FROM wedding) =   06

Classic solution with oracle specific TO_CHAR():

SELECT *
FROM   x
WHERE  TO_CHAR(wedding, 'YYYY-MMM') = '2008-JUN'

(the latter solutions was supported when dinosaurs still walked the earth)

Roland Bouman
Neither will use an index (if one exists) on the `wedding` column.
OMG Ponies
Also, if PLW errors are enabled - both options will result in a conversion away from data type error.
OMG Ponies
@OMG Ponies - yeah, you're right. The between solution is much better for performance. Not sure what you mean by PLW errors though. Do you have a pointer for me? TIA
Roland Bouman
@Roland: Oracle has ORA errors, but also has an additional line of code validation/auditing called PLW (dunno what it stands for). It's not enabled by default as I understand. It's very good for correcting bad habits like using functions on columns/etc.
OMG Ponies
Thanks! I'll look it up.
Roland Bouman
I tried to find a link, but all I get are PLW error specifics :/
OMG Ponies