简体   繁体   中英

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, which 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM