How can I get a table of dates from the first day of the month, two months ago, to yesterday? - sql

I have a situation that I would normally solve by creating a feeder table (for example, every date between five years ago and a hundred years into the future) for querying but, unfortunately, this particular job disallows creation of such a table.
So I'm opening this up to the SO community. Today is Jan 29, 2010. What query could I run that would give a table with a single date column with values ranging from Nov 1, 2009 through Jan 28, 2010 inclusive? On Feb 1, it should give me every date from Dec 1, 2009 through Jan 31, 2010.
I'm using DB2 but I'm happy to see any other solutions on the off-chance they may provide a clue.
I know I can select CURRENT DATE from sysibm.sysdummy1 (or dual for Oracle bods) but I'm not sure how to immediately select a date range without a physical backing table.

This just does sequential days between two dates, but I've posted to show you can eliminate the recursive error by supplying a limit.
with temp (level, seqdate) as
(select 1, date('2008-01-01')
from sysibm.sysdummy1
union all
select level, seqdate + level days
from temp
where level < 1000
and seqdate + 1 days < Date('2008-02-01')
)
select seqdate as CalendarDay
from temp
order by seqdate
Update from pax:
This answer actually put me on the right track. You can get rid of the warning by introducing a variable that's limited by a constant. The query above didn't have it quite right (and got the dates wrong, which I'll forgive) but, since it pointed me to the problem solution, it wins the prize.
The code below was the final working version (sans warning):
WITH DATERANGE(LEVEL,DT) AS (
SELECT 1, CURRENT DATE + (1 - DAY(CURRENT DATE)) DAYS - 2 MONTHS
FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT LEVEL + 1, DT + 1 DAY
FROM DATERANGE
WHERE LEVEL < 1000 AND DT < CURRENT DATE - 1 DAY
) SELECT DT FROM DATERANGE;
which outputs, when run on the 2nd of February:
----------
DT
----------
2009-12-01
2009-12-02
2009-12-03
: : : :
2010-01-30
2010-01-31
2010-02-01
DSNE610I NUMBER OF ROWS DISPLAYED IS 63
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL.

just an idea (not even sure how you'd do this), but let's say you knew how many days you wanted. Like 45 days. If you could get a select to list 1-45 you could do date arithmetic to subtract that number from your reference data (ie today).
This kind of works (in MySQL):
set #i = 0;
SELECT #i:=#i+1 as myrow, ADDDATE(CURDATE(), -#i)
FROM some_table
LIMIT 10;
The trick i have is how to get the 10 to be dynamic. If you can do that then you can use a query like this to get the right number to limit.
SELECT DATEDIFF(DATE_SUB(CURDATE(), INTERVAL 1 DAY),
DATE_SUB(LAST_DAY(CURDATE()), INTERVAL 2 MONTH))
FROM dual;

I haven't used DB2 before but in SQL Server you could do something like the following. Note that you need a table with at least the number of rows as you need days.
SELECT TOP 45
DATEADD(d, ROW_NUMBER() OVER(ORDER BY [Field]) * -1, GETDATE())
FROM
[Table]

Related

Recurring events reminder in SQL

I'm trying to run a simple query to calculate what will be a reminder based upon one date (enrollment_date.) It's a recurring event every 90 days starting with the enrollment date but our staff needs only to see the next possible date. So if one date is in December they will only see that date until it passes and then only see the next after that date has passed. Is that possible? I'm using oracle sql
All that will be seen is:
Until December 12 2015
Client Next Inquiry Date
Client A December 12, 2015
After December 12 2015
Client Next Inquiry Date
Client A March 11 2016
It's not much but this is what I have so far.
SELECT
client_name, enrollment_date,
CASE
WHEN CURRENT_DATE <= DATE(day, 90, nextdue_date)
I think there are still quite a few unknowns with your scenario, but here is an example (for SQL Server) that will show you the next 100 90-day reminders. You can use a CTE to generate a list of reminder dates for each client then use the MIN from that list for each client that is still greater than the current date.
DECLARE #enroll_date DATE = '2015-12-12' --For testing
--DECLARE #enroll_reminder DATE = DATEADD(DAY, 90, #enroll_date)
;WITH cte AS (
SELECT 1 AS count_
UNION ALL
SELECT count_+1
FROM cte
WHERE count_<100
)
SELECT
'Client A'--replace with your column name
,MIN(DATEADD(DAY, 90*count_, #enroll_date)) AS test
FROM cte
--GROUP BY your_column_name
HAVING MIN(DATEADD(DAY, 90*count_, #enroll_date)) > GETDATE()
In this scenario, the next reminder is 2016-03-11, then when that day passes it will show 2016-06-09, then 2016-09-07, etc.
Check if this works for you...
Since this is Oracle (PL/SQL) we cannot use TOP 1 and hence using ROWNUM property.
SELECT client_name as "Client"
, enrollment_date as "Next Inquiry Date"
FROM <table_name>
WHERE enrollment_date < (SYSDATE + 90)
AND ROWNUM = 1
ORDER BY enrollment_date

Adding intervals as part of an SQL statement

Very long shot here as Im not sure this is possible - if it is then I definitely owe you guys.
I have a table with start_date, end_date and hours. Consider I have one line of start_date 1 Jan 2015, end_date of 31 Dec 2015 and hours as 120.
I want to produce a result of 12 lines with 10 hours in each line and the month
so something like
|Jan 15|10|
|Feb 15|10|
...
|Dec 15|10|
I want ten because I am dividing 120 hours by the number of months (12). 120 / 12 = 10
Can I do this at all? Or anything similar? I suspect I may have to do ETL in code rather than in SQL. Has anyone got any ideas on how I could anything to get closer to what I want?
Thanks
You just need a numbers tables. If you had one, you could do:
select add_months(start_date, n.n - 1),
val / (months_between(start_date, end_date) + 1)
from t join
numbers n
on add_months(start_date, n.n - 1) <= end_date;
You can create a numbers table in various ways. An easy way is something like this:
with numbers as (
select rownum as n
from t
where rownum <= 100
)

Oracle correctly getting the month difference

Hi Ive been having an issue with getting the correct difference in a date from the current month not including the day.
ie if the month when the query is run is march 2013
then the following should be the result
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 2
however using the below sql statement im getting
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 1
select EXECUTION_DATE,
floor(MONTHS_BETWEEN (trunc(sysdate,'MM')-1, EXECUTION_DATE))+1 "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
Please can someone put me right ive been bashing my head with this for some time now
thanks
select EXECUTION_DATE,
MONTHS_BETWEEN (trunc(sysdate,'MM'), trunc(EXECUTION_DATE,'MM')) "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
Not looking for scores but cannot understand what is the problem with months_between? In my understanding it does not matter when in month execution takes place - Jan-31 or Jan 30... The difference is still 2 months between Jan and Mar as in your example. I can add more days in month in the query but mo_betw. will still be the same...:
SELECT to_char(exec_date, 'DD-MON-YYYY') exec_date, MONTHS_BETWEEN(run_date, exec_date) months_btwn
FROM
(
SELECT to_date('01/03/2013', 'DD/MM/YYYY') run_date
, Add_Months(Trunc(sysdate,'YEAR'),Level-1) exec_date -- first day of each month
FROM dual
CONNECT BY LEVEL <= 3
)
/
EXEC_DATE MONTHS_BTWN
------------------------
01-JAN-2013 2
01-FEB-2013 1
01-MAR-2013 0
Months_Between has complex logic that takes the day of the month into account.
Perhaps what you want is this:
select EXECUTION_DATE,
((year(sysdate)*12+month(sysdate)) - (year(execution_date)*12 + month(execution_date))
) as Exec_Diff
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
This converts the year/month combination into the number of months since 0 time and then subtracts the results.

How To Find First Date of All MOnths In A Year

Hello every One i am trying to get Ist date of All months in A year
Like if Curretn year is 2012 and i want to get folowing results from a query
like
1-JAN-2012
1-FEB-2012
1-APR-2012
.
.
.
.
.
.
1-DEC-2012
Is there any one who can solve my problem thanks in advance
Just for completeness - here's a simpler version:
select ADD_MONTHS(TRUNC(SYSDATE,'Y'),ROWNUM-1)
from dual connect by level <= 12;
A calendar table is easier to use. Where I work, for example, you'd just run this query.
select cal_date
from calendar
where year_of_date = 2012
and day_of_month = 1;
There's a lot to be said for a query being obvious.
Please try the following. You may want to tweak the date format/timezone
select to_date('2012/'||l||'/01', 'yyyy/mm/dd')
from (select level l from dual connect by level < 13)
EDIT: As provided by the op in the comments, the current year needs to be taken rather than hardcoding it. The updated query is
SELECT L || '/01/' || TO_CHAR (SYSDATE, 'YYYY') DATESS FROM
(SELECT LEVEL L FROM DUAL CONNECT BY LEVEL < 13)
If you want to use solely date functions to get the value for a specific year you can use the following, also SQL Fiddle'd:
select add_months(trunc(last_day(add_months(trunc(to_date('2011'
,'yyyy')
, 'y')
, -1)
) + 1
)
, level - 1)
from dual
connect by level <= 12
This turns your "year" into a date, truncates that to the 1st of January as by default to_date('2011', 'yyyy') returns the current date in that year. It then removes a month, taking us to the 1st December 2010. Get's the last day of that month, the 31st December and adds a day, so back to the 1st of January, but I also do a connect by level and add the level - 1, i.e. 0 in January to return the correct day.
Unfortunately, Oracle doesn't have a first_day function, which would make this a lot easier.
It's roughly the same for the current year:
select add_months(trunc(last_day(add_months(trunc(sysdate,'y'),-1)) + 1), level - 1)
from dual
connect by level <= 12

Add date without exceeding a month

I hope someone could help me on this.
I want to add a month to a database date, but I want to prevent two jumping over month on those days at the end.
For instance I may have:
Jan 31 2009
And I want to get
Feb 28 2009
and not
March 2 2009
Next date would be
March 28 2009
Jun 28 2009
etc.
Is there a function that already perform this kind of operation in oracle?
EDIT
Yeap. I want to copy each month all the records with some status to the next ( so the user don't have to enter again 2,000 rows each month )
I can fetch all the records and update the date manually ( well in an imperative way ) but I would rather let the SQL do the job.
Something like:
insert into the_table
select f1,f2,f3, f_date + 30 /* sort of ... :S */ from the_Table where date > ?
But the problem comes with the last day.
Any idea before I have to code something like this?
for each record in
createObject( record )
object.date + date blabala
if( date > 29 and if februrary and the moon and the stars etc etc 9
end
update.... et
EDIT:2
Add months did the trick.
now I just have this:
insert into my_table
select f1, add_months( f2, 1 ) from my_table where status = etc etc
Thanks for the help.
Oracle has a built-in function ADD_MONTHS that does exactly that:
SQL> select add_months(date '2008-01-31',1) from dual;
ADD_MONTHS(
-----------
29-FEB-2008
SQL> select add_months(date '2008-02-29',1) from dual;
ADD_MONTHS(
-----------
31-MAR-2008
I think you're looking for LAST_DAY:
http://download.oracle.com/docs/cd/B28359_01/olap.111/b28126/dml_functions_2006.htm
I just did:
select add_months(TO_DATE('30-DEC-08'), 2) from dual
and got
28-FEB-2009
No need to use LAST_DAY. If you went that route, you could create a function that:
1. takes a date
2. Changes the day to the first of the month.
3. Add a month.
4. Changes the day to the LAST_DAY for that month.
I think you'll have to write it on your own, My advice is first to evaluate the "last day of the month" with this method:
Add one month (not 30 days, one month!)
Find first day of the month (should be easy)
substract one day
Then compare it to your "plus x days" value, and choose the lowest one (I understood the logic behind the jump from 31/Jan to 28/Feb, but I don't get it for the jump from 28-Feb to 28-Mar)
It sounds like you want the current month plus one (with appropriate rollover in December)
and the minimum of the last day of that month and the current day.