views:

334

answers:

1

I have a monthly table (only holds rows with first day of month, and unique constraint so only one of each) and a daily table with similar information for each day (same deal, only one per day):

Monthly table       Daily table
-------------       -----------
2009-01-01          2009-01-01
2009-02-01          2009-01-02
: :                 : :
2009-09-01          2009-01-31
                    2009-02-01
                    : :
                    2009-02-28
                    2009-03-01
                    : :
                    2009-09-01

but there may be days missing.

I want to run a query that returns, for each date in the monthly table, that date along with the minimum and maximum dates for that month in the daily table (using standard SQL preferably of DB2-specific if absolutely necessary).

So, if the last week of January and first week of February is missing, I need:

MonthStart  FirstDay    LastDay
----------  ----------  ----------
2009-01-01  2009-01-01  2009-01-24
2009-02-01  2009-02-08  2009-02-28
: :
2009-09-01  2009-09-01  2009-01-30

Here's the query I have:

select m.date as m1,               
       dx.d1 as m2,                          
       dx.d2 as m3                           
from   monthly m,              
       ( select min(d.date) as d1,
                max(d.date) as d2        
         from   daily d            
         where  month(d.date) = month(m.date)
         and    year(d.date) = year(m.date)    
       ) as dx;

but I'm getting the error:

DSNT408I SQLCODE = -206, ERROR: M.DATE IS NOT A COLUMN OF
AN INSERTED TABLE, UPDATED TABLE, OR ANY TABLE IDENTIFIED
IN A FROM CLAUSE, OR IS NOT A COLUMN OF THE TRIGGERING
TABLE OF A TRIGGER
DSNT418I SQLSTATE = 42703 SQLSTATE RETURN CODE

Does anyone have any advice on how best to do this? I'm new to sub-selects.

+2  A: 
SELECT m.date as m1,               
       MIN(d.date) as m2,                          
       MAX(d.date) as m3
       -- COUNT(d.date) as NbOfDays  -- if so desired...                          
FROM monthly m
JOIN daily d ON month(d.date) = month(m.date) and year(d.date) = year(m.date) 
WHERE -- some condition
GROUP BY m.date
ORDER BY m.date -- or something else...

Note that this type of query (as the other ones shown in the question and in responses so far, are relatively slow, as they imply a table scan so the month(x) and year(x) can be calculated for each [qualifying] row. (i.e. putting a range on date in the WHERE clause would of course help). If this type of query is ran frequently and if the size of table is significant, i**t may be useful to add a column for these computed values** (or possibly for the combined value (Year-Month), so that not only the calculation is unnecessary but the underlying column(s) can be indexed.

mjv
We've thought of the performance implications but it's a limited historical database. We only ever have 24 months in the monthly table and 700-odd days in the daily table. Performance won't be a problem. But it wouldn't be a full table scan if there are indexes on the date fields, surely?
paxdiablo
Perfect, gave me exactly what I wanted. Cheers, +1 and accept.
paxdiablo
If you're performing computations on the indexed fields in order to match them, the indexes will be ignored unless you add a column and create indexes for that computation, as mjv suggested.
Randolph Potter