Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
SELECT 1
FROM DUAL
CONNECT BY LEVEL <= <n>
Option 2:
SELECT 1
FROM DUAL
GROUP BY CUBE (<n comma separated numbers or characters>)
Option 3:
SELECT dim
FROM dual
MODEL
DIMENSION BY (0 dim)
MEASURES (0 rnum)
RULES ITERATE (<n>) (
rnum [ITERATION_NUMBER] = ITERATION_NUMBER
);
First we will generate a row-source of sequential numbers using a single SQL on the
DUAL table of Oracle. Then we will manipulate the row-source to generate meaningful
dates out of it.
From Oracle Documentation: ?CUBE takes a specified set of grouping columns and
creates subtotals for all of their possible combinations??. If n columns are
specified for a CUBE, there will be 2 to the n combinations of subtotals returned.?
In one month, there can be maximum 31 days. The nearest integer > 31 which is a
power of 2 is 32.
Hence, from the definition of CUBE above, if we pass five digits to the CUBE
function, we should obtain a source of 32 rows.
SELECT 1
FROM Dual
GROUP BY CUBE (2, 2, 2, 2, 2);
Note: In this case, just for the sake of clarity we have passed five 2's. You can
choose any number or characters to the CUBE function to achieve the same result
e.g.
We will wrap the above SQL in an inline view and restrict the row-source to 31 rows
using ROWNUM pseudo-column.
Thus, the above SQL will give us a sequential series of rows from 1 to 31.
Hence if we add (ROWNUM-1) value to each row, we will get the series of dates in
the current month, starting from the first date of the month.
But every month will not have 31 days. So, for the months having 30 days or 28 days
or 29 days, the sequential values added will exceed the last day of current month
and will generate rows for next month as well.
If we execute the following query, we will see that the boundary values are
exceeded and the dates for the subsequent month are also getting included.
?ADD_MONTHS returns the date ?date? plus ?integer? months. The date argument can be
a datetime value or any value that can be implicitly converted to DATE. The ?
integer? argument can be an integer or any value that can be implicitly converted
to an integer. The return type is always DATE, regardless of the datatype of ?
date?.
If ?date? is the last day of the month or if the resulting month has fewer days
than the day component of date, then the result is the last day of the resulting
month. Otherwise, the result has the same day component as ?date?.?
With the above usage in our mind, we can easily conclude that if we pass 1 as ?
integer? to the ADD_MONTHS function, with the ?date? as the First Day of the Month,
we will obtain the first day of the next month.
From here, the math is easy. The difference between the first day of next month and
first day of current month will give us the exact number of days in the current
month. Also note that Oracle Date functions (and not exactly our logic) will now
take care of the number of days in a month. Even if the year is a leap year, Oracle
will determine the appropriate number of days.
SELECT ADD_MONTHS(TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM'),1)
FIRST_DAY_OF_NEXT_MONTH ,
TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM') FIRST_DAY_OF_CURRENT_MONTH ,
ADD_MONTHS(TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM'),1) -
TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM') NO_OF_DAYS_IN_CURRENT_MONTH
FROM DUAL;
We can try the above SQL with any date, even February month of a leap year. The
result will always be accurate for any month.
Hence, in order to generate all the dates for the month of April, the query will be
as follows:-
From the above SQL, we now have all the dates in the month.
We just need to exclude the Saturday and Sunday to finally get the complete result-
set of working days.
We will wrap-up the above query in an inline view and then apply a WHERE clause to
filter out the Saturdays and Sundays.
The following will be the final query to generate the Working Days.
SELECT * FROM
(
SELECT TRUNC(TO_DATE('20080415','yyyymmdd'),'MM')+ROWNUM -1 DATES FROM
(
SELECT 1
FROM Dual
GROUP BY CUBE (2, 2, 2, 2, 2)
)
WHERE ROWNUM <= ADD_MONTHS(TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM'),1) -
TRUNC(TO_DATE('20080415','YYYYMMDD'),'MM')
)
WHERE TO_CHAR( DATES, 'DY') NOT IN ('SAT','SUN');
In this case the approach will be same, but there will be a small change in the
arithmetic.
A year consists of maximum 366 days. The nearest integer > 366 which is a power of
2 is 512.
Also, we need to modify t he ADD_MONTHS and TRUNC functions to calculate the number
of rows for a year. In this case also, any special date handling (e.g. the leap
year consideration) will be taken care by Oracle.
SELECT * FROM
(
SELECT TRUNC(TO_DATE('20080415','yyyymmdd'),'Y')+ROWNUM -1 DATES FROM
(
SELECT 1
FROM Dual
GROUP BY CUBE (2, 2, 2, 2, 2, 2, 2, 2, 2)
)
WHERE ROWNUM <= ADD_MONTHS(TRUNC(TO_DATE('20080415','YYYYMMDD'),'Y'),12) -
TRUNC(TO_DATE('20080415','YYYYMMDD'),'Y')
)
WHERE TO_CHAR( DATES, 'DY') NOT IN ('SAT','SUN');
Notice the sections in the above query which is coloured blue. To fetch the working
days for the current year, that is the only change made to the Query discussed and
formulated in Section 1.
SQL to determine the first and last working day of the month for a given date:
We will extend the concept of the query of section 1. The following query will
provide the first and last working day of the month for a given date.
SQL to determine the first and last working day of each month in the year for a
given date:
We will extend the concept of the query in the section 2.
The following query will give us the first and last working days in each month of
the year.
After the row-source is generated, we will convert them to the ASCII character
using the Oracle built in function called ?ascii?.
Finally we will filter out the rows for which only the alphabets are present.
The following SQL will generate a series of letters from A to Z in upper and lower
case: