views:

81

answers:

3

Here's my query:

select * 
 from test n
WHERE lower(process_name) like 'test%'
  AND (   test_id is NULL 
       OR TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE),-6),'YYYYMM') > TO_CHAR(n.process_date,'YYYYMM')

I want check whether date field process_date is greater than 6 months in the query.

A: 

Hi Arav,

If you're using SQL Server, you can use DATEDIFF(). See below example.

DECLARE @a AS DATETIME = '2010-6-1 00:00'; -- Assignment and declaration in SQLS2008
DECLARE @b AS DATETIME = '2010-8-16 00:15';

-- usage: DATEDIFF(Interval, StartDate, EndDate)

SELECT      DATEDIFF(MONTH, @a, @b) AS MonthDifference,
            DATEDIFF(HOUR, @a, @b) AS HourDifference,
            DATEDIFF(MINUTE, @a, @b) AS MinuteDifference;

You can deduct an answer from this. Please let me know if I've missed the target.

Thanks.

lb
OMG Ponies
My bad. Thanks for the notification.
lb
i am using oracle 10g
Arav
+2  A: 

I don't have an Oracle instance handy to test if Oracle will do implicit data type conversion on the TO_CHAR results being that it will be entirely numeric. Still, seems over complicated to me when comparing to a TRUNC'd DATE value...

For records that are six months or older in Oracle:

n.process_date <= ADD_MONTHS(TRUNC(SYSDATE), -6)

If you want older but not including six months exactly - remove the equals operator:

n.process_date < ADD_MONTHS(TRUNC(SYSDATE), -6)

For records that are six months or older in MySQL:

n.process_date <= DATE(DATE_SUB(NOW(), INTERVAL 6 MONTH))

If you want older but not including six months exactly - remove the equals operator:

n.process_date < DATE(DATE_SUB(NOW(), INTERVAL 6 MONTH))

For MySQL, DATE is performing similar to Oracle's TRUNC.

OMG Ponies
Is the tochar query listed in post is a correct way of doing?TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE),-6),'YYYYMM') > TO_CHAR(n.process_date,'YYYYMM')
Arav
@Arav: I don't think TO_CHAR is necessary - you already have the DATE to compare with
OMG Ponies
@OMG Ponies: I guess his intension is to compare month numbers, see 2nd SELECT in my post
Alexander Malakhov
+1 never use TO_CHAR when comparing dates.
Jeffrey Kemp
I want to compare only YYYYMM part of date. How can i modify the above query
Arav
@Arav: `LAST_DAY(process_date) < ADD_MONTHS(LAST_DAY(SYSDATE), -6)` this is guaranteed by Oracle to give same result as YYYYMM
Alexander Malakhov
Although this disables the index again - unless we create a functional index on LAST_DAY(process_date). However, I think process_date < ADD_MONTHS(LAST_DAY(TRUNC(SYSDATE)),-6) + 1 should give the right result - for today, 12th August, it gives a cut-off of midnight on 1st March 2010.
JulesLt
+1  A: 
SELECT *
  FROM test
 WHERE MONTHS_BETWEEN( SYSDATE, process_date ) > 6

MONTHS_BETWEEN( date1, date2) returns (date1 - date2), so order of args is significant

If you want the months' numbers to differ by 6, for example if this is wrong for you

    MONTHS_BETWEEN( 'JUN 13 2010', 'JAN 16 2010') == 5.9 

Then you should:

SELECT *  
  FROM test
 WHERE MONTHS_BETWEEN( LAST_DAY(SYSDATE), LAST_DAY(process_date) ) >= 6

Last days of months are guaranteed to compare correctly and return whole number


NOTE: both those queries will not use index on "process_date", if its available. For 'indexed' solution see post by OMG Ponies and comments to this one

Alexander Malakhov
That won't be able to use an index if one exists on `process_date`.
OMG Ponies
@OMG Ponies: you are right * sigh *, I've checked this with Oracle 11gR2. Note, if behavior of the second SELECT is needed, your query also will not use index
Alexander Malakhov
I think(!) if a function based index on (last_day(process_date)) is created, the second query should actually benefit from that index.
a_horse_with_no_name
@a_horse_with_no_name: no, `MONTHS_BETWEEN` prevents index usage, I've checked exec plan. And anyway I realized, that `LAST_DAY` on process_date isn't necessary
Alexander Malakhov