开发者

Date arithmetic in SQL on DB2/ODBC

I'm building a query against a DB2 database, connecting through the IBM Client Access ODBC driver. I want to pull fields that are less than 6 days old, based on the field 'a.ofbkddt'... the problem is that this field is not a date field, but rather a DECIMAL field, formatted as YYYYMMDD.

I was able to break down the decimal field by wrapping it in a call to char(), then using substr() to pull the year, month and day fields. I then formatted this as a date, and called the days() function, whi开发者_开发百科ch gives a number that I can perform arithmetic on.

Here's an example of the query:

select
       days( current date) -
       days( substr(char(a.ofbkddt),1,4) concat '-'              -- YYYY-
             concat substr(char(a.ofbkddt),5,2) concat '-'       -- MM-
             concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
       a.ofbkddt as mydate
from QS36F.ASDF a

This yields the following:

difference  mydate
2402        20050402
2025        20060306
...
4           20110917
3           20110918
2           20110919
1           20110920

This is what I expect to see... however when I use the same logic in the where clause of my query:

select
       days( current date) -
       days( substr(char(a.ofbkddt),1,4) concat '-'              -- YYYY-
             concat substr(char(a.ofbkddt),5,2) concat '-'       -- MM-
             concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
       a.ofbkddt as mydate
from QS36F.ASDF a
where
(
days( current date) -
days( substr(char(a.ofbkddt),1,4) concat '-'         -- YYYY-
      concat substr(char(a.ofbkddt),5,2) concat '-'  -- MM
      concat substr(char(a.ofbkddt),7,2) )           -- DD
) < 6

I don't get any results back from my query, even though it's clear that I am getting date differences of as little as 1 day (obviously less than the 6 days that I'm requesting in the where clause).

My first thought was that the return type of days() might not be an integer, causing the comparison to fail... according to the documentation for days() found at http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/db2/rbafzmst02.htm, it returns a bigint. I cast the difference to integer, just to be safe, but this had no effect.


You're going about this backwards. Rather than using a function on every single value in the table (so you can compare it to the date), you should pre-compute the difference in the date. It's costing you resources to run the function on every row - you'd save a lot if you could just do it against CURRENT_DATE (it'd maybe save you even more if you could do it in your application code, but I realize this might not be possible). Your dates are in a sortable format, after all.

The query looks like so:

SELECT ofbkddt as myDate
FROM QS36F.ASDF
WHERE myDate > ((int(substr(char(current_date - 6 days, ISO), 1, 4)) * 10000) +
                (int(substr(char(current_date - 6 days, ISO), 6, 2)) * 100) +
                (int(substr(char(current_date - 6 days, ISO), 9, 2))))

Which, when run against your sample datatable, yields the following:

myDate
=============
20110917
20110918
20110919
20110920

You might also want to look into creating a calendar table, and add these dates as one of the columns.


What if you try a common table expression?

WITH A AS
(
    select
       days( current date) -
       days( substr(char(a.ofbkddt),1,4) concat '-'              -- YYYY-
             concat substr(char(a.ofbkddt),5,2) concat '-'       -- MM-
             concat substr(char(a.ofbkddt),7,2) ) as difference, -- DD
       a.ofbkddt as mydate
    from QS36F.ASDF a
)
SELECT
    *
FROM
    a
WHERE
    difference < 6


Does your data have some nulls in a.ofbkddt? Maybe this is causing some funny behaviour in how db2 is evaluating the less than operation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜