How to get all days in month? [duplicate] - sql

This question already has answers here:
How to populate calendar table in Oracle?
(3 answers)
Closed 8 years ago.
Possible to get all days in month in Oracle SQL/PLSQL as table ?
select * from bla-bla-bla DUAL
results:
1 rec: 01.01.2012
2 rec: 02.01.2012
3 rec: 03.01.2012
...
4 rec: 31.01.2012
?

this is what you are looking for;
select to_date('01.01.2012','dd.mm.yyyy')+level-1
from dual
connect by level <= TO_CHAR(LAST_DAY(to_date('01.01.2012','dd.mm.yyyy')),'DD')

ADD_MONTHS (dt, 1) - dt is also an alternative.
For a particular month of an year, you need to hardcode the date :
WITH d AS
(SELECT TRUNC ( to_date('01.01.2012','dd.mm.yyyy'), 'MM' ) - 1 AS dt
FROM dual
)
SELECT dt + LEVEL
FROM d
CONNECT BY LEVEL <= ADD_MONTHS (dt, 1) - dt
/
Else, to get the list for current month, simply use SYSDATE instead of hardcoding the date :
SQL> WITH d AS
2 (SELECT TRUNC(sysdate,'MM') -1 AS dt FROM dual
3 )
4 SELECT dt + LEVEL
5 FROM d
6 CONNECT BY LEVEL <= ADD_MONTHS (dt, 1) - dt
7 /
DT+LEVEL
---------
01-OCT-14
02-OCT-14
03-OCT-14
04-OCT-14
05-OCT-14
06-OCT-14
07-OCT-14
08-OCT-14
09-OCT-14
10-OCT-14
11-OCT-14
12-OCT-14
13-OCT-14
14-OCT-14
15-OCT-14
16-OCT-14
17-OCT-14
18-OCT-14
19-OCT-14
20-OCT-14
21-OCT-14
22-OCT-14
23-OCT-14
24-OCT-14
25-OCT-14
26-OCT-14
27-OCT-14
28-OCT-14
29-OCT-14
30-OCT-14
31-OCT-14
31 rows selected.
SQL>

Related

split from date and To date in multiple months using oracle sql

In need to split lines with From date and To date in multiple months.
I want to split like this.Target
Sample 1
10/02/2023 - 28/02/2023
Target
10/02/2023 - 28/02/2023
Sample 2
10/02/2023 - 29/08/2023
Target
10/02/2023 - 28/02/2023
01/03/2023 - 31/03/2023
01/04/2023 - 29/08/2023
Sample 3
01/04/2022 - 31/03/2023
Target
01/04/2022 - 28/02/2023
01/03/2023 - 31/03/2023
I succeed in first steps but I'm now stucked
For the moment I can only do like this[Existing]
But in yellow wrong values,
Here below my code
CASE WHEN qd.valid_from >= TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')
THEN
TRUNC(qd.valid_from)
ELSE
TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')
END new_start_date,
CASE WHEN last_day(TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')) >= last_day(TRUNC(add_months(qd.valid_from,2),'MM'))
THEN
TRUNC(qd.valid_to)
ELSE
TRUNC(last_day(TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')))
END new_end_date
FROM QUOTATIONS_UO QH
),
TABLE(
CAST(
MULTISET
(
SELECT LEVEL
FROM dual
CONNECT BY add_months(TRUNC(qd.valid_from,'MM'),LEVEL - 1) <= add_months(TRUNC(qd.valid_from,'MM'),2)
) AS sys.OdciNumberList
)
)
)
It is unclear what is it about months february and march vs all the others, but if you want to split dates by months then maybe this could help you:
Select DISTINCT
ID,
LEVEL "LVL",
CASE WHEN LEVEL = 1 THEN FROM_DATE END "FROM_DATE",
CASE WHEN LEVEL = 1 THEN UNTIL_DATE END "UNTIL_DATE",
CASE WHEN MONTH_UNTIL = MONTH_FROM THEN FROM_DATE
WHEN LEVEL = 1 THEN FROM_DATE
WHEN MONTHS > 1 And LEVEL < MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
WHEN MONTHS > 1 And LEVEL = MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
WHEN MONTHS > 0 And MONTHS < LEVEL THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
ELSE UNTIL_DATE
END "FROM_DATE_2",
--
CASE WHEN MONTH_UNTIL = MONTH_FROM THEN UNTIL_DATE
--WHEN LEVEL = 1 THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
WHEN MONTHS > 1 And LEVEL < MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
WHEN MONTHS > 1 And LEVEL = MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
ELSE UNTIL_DATE
END "UNTIL_DATE_2"
FROM
(
Select
ID, FROM_DATE, UNTIL_DATE,
To_Char(FROM_DATE, 'yyyymm') "MONTH_FROM",
To_Char(UNTIL_DATE, 'yyyymm') "MONTH_UNTIL",
FLOOR(MONTHS_BETWEEN(UNTIL_DATE, FROM_DATE)) "MONTHS"
From
tbl
)
CONNECT BY LEVEL < MONTHS + 2
ORDER BY ID, LVL
... which with sample data like here:
WITH
tbl (ID, FROM_DATE, UNTIL_DATE) AS
(
Select 1, To_Date('10.02.2023', 'dd.mm.yyyy'), To_Date('28.02.2023', 'dd.mm.yyyy') From Dual Union All
Select 2, To_Date('10.02.2023', 'dd.mm.yyyy'), To_Date('29.08.2023', 'dd.mm.yyyy') From Dual Union All
Select 3, To_Date('01.04.2022', 'dd.mm.yyyy'), To_Date('31.03.2023', 'dd.mm.yyyy') From Dual
)
... results as:
ID LVL FROM_DATE UNTIL_DATE FROM_DATE_2 UNTIL_DATE_2
---------- ---------- --------- ---------- ----------- ------------
1 1 10-FEB-23 28-FEB-23 10-FEB-23 28-FEB-23
2 1 10-FEB-23 29-AUG-23 10-FEB-23 28-FEB-23
2 2 01-MAR-23 31-MAR-23
2 3 01-APR-23 30-APR-23
2 4 01-MAY-23 31-MAY-23
2 5 01-JUN-23 30-JUN-23
2 6 01-JUL-23 31-JUL-23
2 7 01-AUG-23 29-AUG-23
3 1 01-APR-22 31-MAR-23 01-APR-22 30-APR-22
3 2 01-MAY-22 31-MAY-22
3 3 01-JUN-22 30-JUN-22
3 4 01-JUL-22 31-JUL-22
3 5 01-AUG-22 31-AUG-22
3 6 01-SEP-22 30-SEP-22
3 7 01-OCT-22 31-OCT-22
3 8 01-NOV-22 30-NOV-22
3 9 01-DEC-22 31-DEC-22
3 10 01-JAN-23 31-JAN-23
3 11 01-FEB-23 28-FEB-23
3 12 01-MAR-23 31-MAR-23

oracle sql query months

I'm fairly new to SQL and I have a question regarding a query.
I would like to use a "with-clause" to create a temporary table that displays all months between two dates.
I will then use this temporary table to apply a filter to my actual table.
My query:
WITH monlist(mon, next_mon) as (
select add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level - 1), add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level)
from dual
connect by level <= (months_between(to_date(:P6_DATUM_BIS,'DD-MM-YYYY'), to_date(:P6_DATUM_VON,'DD-MM-YYYY')))
The problem is that I want to narrow it down to days, i.e. if I want to start from 05-01-2022 (DD-MM-YYY), this is not possible.
The temporary table starts with the beginning of the month (01-01-2022).
It is similar with the end - it is rounded up to the full month.
Is there a way to change the query so that the initial and final values are accepted correctly?
I would like to get the following output:
mon next_mon
05-01.2022 - 01-02-2022
01-02-2022 - 28-02-2022
...
01-10-2022 - 15-10-2022 (If end-date is 15-10-2022)
If it were PL/SQL, you'd use IF-THEN-ELSE; in SQL, use CASE expression. Something like this (example ran in SQL*Plus, hence substitution variables):
SQL> alter session set nls_date_format = 'dd-mm-yyyy';
Session altered.
SQL> set ver off
SQL>
SQL> WITH monlist as
2 (select add_months(trunc(to_date('&&P6_DATUM_VON','DD-MM-YYYY'), 'MM'), level - 1) mon,
3 add_months(trunc(to_date('&&P6_DATUM_VON','DD-MM-YYYY'), 'MM'), level) next_mon,
4 level lvl
5 from dual
6 connect by level <= months_between(to_date('&&P6_DATUM_BIS','DD-MM-YYYY'),
7 to_date('&&P6_DATUM_VON','DD-MM-YYYY')
8 ) + 1
9 )
10 select case when lvl = 1
11 then to_date('&&P6_DATUM_VON','DD-MM-YYYY') else mon end mon,
12 case when lvl = (select max(lvl) from monlist)
13 then to_date('&&P6_DATUM_BIS','DD-MM-YYYY') else next_mon end next_mon
14 from monlist
15 order by lvl;
Enter value for p6_datum_von: 05-01-2022
Enter value for p6_datum_bis: 15-10-2022
MON NEXT_MON
---------- ----------
05-01-2022 01-02-2022
01-02-2022 01-03-2022
01-03-2022 01-04-2022
01-04-2022 01-05-2022
01-05-2022 01-06-2022
01-06-2022 01-07-2022
01-07-2022 01-08-2022
01-08-2022 01-09-2022
01-09-2022 01-10-2022
01-10-2022 15-10-2022
10 rows selected.
SQL>
In Apex (you do use it, right? Regarding :P6_... item names?), that would be just
WITH monlist as
(select add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level - 1) mon,
add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level) next_mon,
level lvl
from dual
connect by level <= months_between(to_date(:P6_DATUM_BIS,'DD-MM-YYYY'),
to_date(:P6_DATUM_VON,'DD-MM-YYYY')
) + 1
)
select case when lvl = 1
then to_date(:P6_DATUM_VON,'DD-MM-YYYY') else mon end mon,
case when lvl = (select max(lvl) from monlist)
then to_date(:P6_DATUM_BIS,'DD-MM-YYYY') else next_mon end next_mon
from monlist
order by lvl;

How to include values that count nothing on certain day (APEX)

I have this query:
SELECT
COUNT(ID) AS FREQ,
TO_CHAR(TRUNC(CREATED_AT),'DD-MON') DATES
FROM TICKETS
WHERE TRUNC(CREATED_AT) > TRUNC(SYSDATE) - 32
GROUP BY TRUNC(CREATED_AT)
ORDER BY TRUNC(CREATED_AT) ASC
This counts how many tickets where created every day for the past month.
The result looks something like this: (first 10 rows)
FREQ DATES
3 28-DEC
4 04-JAN
8 05-JAN
1 06-JAN
4 07-JAN
5 08-JAN
2 11-JAN
6 12-JAN
3 13-JAN
8 14-JAN
The linechart that I created looks like this:
The problem is that the days where tickets are not created (in particular the weekends) the line just goes straight to the day where there is created a ticket.
Is there a way in APEX or in my query to include the days that aren't counted?
As commented, using one of row generator techniques you'd create a "calendar" table and outer join it with a table that contains data you're displaying.
Something like this (see comments within code):
SQL> with yours (amount, datum) as
2 -- your sample table
3 (select 100, date '2021-01-01' from dual union all
4 select 200, date '2021-01-03' from dual union all
5 select 300, date '2021-01-07' from dual
6 ),
7 minimax as
8 -- MIN and MAX date (so that they could be used in row generator --> CALENDAR CTE (below)
9 (select min(datum) min_datum,
10 max(datum) max_datum
11 from yours
12 ),
13 calendar as
14 -- calendar, from MIN to MAX date in YOUR table
15 (select min_datum + level - 1 datum
16 from minimax
17 connect by level <= max_datum - min_datum + 1
18 )
19 -- final query uses outer join
20 select c.datum,
21 nvl(y.amount, 0) amount
22 from calendar c left join yours y on y.datum = c.datum
23 order by c.datum;
DATUM AMOUNT
---------- ----------
01.01.2021 100
02.01.2021 0
03.01.2021 200
04.01.2021 0
05.01.2021 0
06.01.2021 0
07.01.2021 300
7 rows selected.
SQL>
Applied to your current query:
WITH
minimax
AS
-- MIN and MAX date (so that they could be used in row generator --> CALENDAR CTE (below)
(SELECT MIN (created_at) min_datum, MAX (created_at) max_datum
FROM tickets),
calendar
AS
-- calendar, from MIN to MAX date in YOUR table
( SELECT min_datum + LEVEL - 1 datum
FROM minimax
CONNECT BY LEVEL <= max_datum - min_datum + 1)
-- final query uses outer join
SELECT COUNT (t.id) AS freq, TO_CHAR (TRUNC (c.datum), 'DD-MON') dates
FROM calendar c LEFT JOIN tickets t ON t.created_at = c.datum
WHERE TRUNC (t.created_at) > TRUNC (SYSDATE) - 32
GROUP BY TRUNC (c.datum)
ORDER BY dates ASC
I added a with clause to generate last 31 days, then I left joined with your base table like below.
with last_31_days as (
select trunc(sysdate) - 32 + level dt from dual connect by trunc(sysdate) - 32 + level < trunc(sysdate)
)
SELECT
nvl(COUNT(t.ID), 0) AS FREQ,
TO_CHAR(
nvl(TRUNC(t.CREATED_AT), a.dt)
,'DD-MON') DATES
FROM last_31_days a
LEFT JOIN TICKETS t
ON TRUNC(t.CREATED_AT) = a.dt
GROUP BY nvl(TRUNC(t.CREATED_AT), a.dt)
ORDER BY 2 ASC
;
#Littlefoot answer is perfect. but here is a cheeky way to get the similar table with format match OP output. using a simple cte for this.
WITH cte AS (
SELECT To_Char(Trunc(SYSDATE - ROWNUM),'DD-MON') dtcol
FROM DUAL
CONNECT BY ROWNUM < 366
)
SELECT * FROM cte
here is db<>fiddle
and then you can simply join this cte to fill up empty date. as the origin output column date looks like a string column.
connect by is for oracle only. but I think you can still use recursive cte to get similar result in other DBMS support recursive cte.

Counting the number of days excluding sunday between two dates

I am trying to calculate number of days betwen two dates excluding sundays. This is my query,
SELECT F_PLANHM_END_DT
- F_PLANHM_ST_DT
- 2
* (TO_CHAR (F_PLANHM_END_DT, 'WW') - TO_CHAR (F_PLANHM_ST_DT, 'WW'))
FROM VW_S_CURV_PROC
WHERE HEAD_MARK = 'IGG-BLH-BM 221';
SELECT COUNT (*)
FROM (SELECT SYSDATE + l trans_date
FROM ( SELECT LEVEL - 1 l
FROM VW_S_CURV_PROC
CONNECT BY LEVEL <= ( (SYSDATE + 7) - SYSDATE)))
WHERE TO_CHAR (trans_date, 'dy') NOT IN ('sun');
I am retrieving date from a view called VW_S_CURV_PROC with start date : F_PLANHM_ST_DT and end date F_PLANHM_END_DT. Somehow i cant make this to work. Please help me...
You could use the ROW GENERATOR technique to first generate the dates for a given range, and then exclude the SUNDAYs.
For example, this query will give me the total count of days between 1st Jan 2014 and 31st Dec 2014, excluding the Sundays -
SQL> WITH DATA AS
2 (SELECT to_date('01/01/2014', 'DD/MM/YYYY') date1,
3 to_date('31/12/2014', 'DD/MM/YYYY') date2
4 FROM dual
5 )
6 SELECT SUM(holiday) holiday_count
7 FROM
8 (SELECT
9 CASE
10 WHEN TO_CHAR(date1+LEVEL-1, 'DY','NLS_DATE_LANGUAGE=AMERICAN') <> 'SUN'
11 THEN 1
12 ELSE 0
13 END holiday
14 FROM data
15 CONNECT BY LEVEL <= date2-date1+1
16 )
17 /
HOLIDAY_COUNT
-------------
313
SQL>

extracting total days of a month and then use it to get average sales per day

Hi i've been working on this project and need to get this.
SELECT sf.ORDER_QNT, dd.ACTUAL_DATE, dd.MONTH_NUMBER
FROM sales_fact sf,
date_dim dd
WHERE dd.date_id = sf.date_id
AND dd.MONTH_NUMBER = 1;
the result is the following:
ORDER_QNT ACTUAL_DATE MONTH_NUMBER
---------- ----------- ------------
1100 05/01/13 1
100 05/01/13 1
140 06/01/13 1
110 07/01/13 1
200 08/01/13 1
500 08/01/13 1
230 08/01/13 1
500 08/01/13 1
200 08/01/13 1
53 15/01/13 1
53 22/01/13 1
Now, I want to get the average for that month (average per day).
SELECT sum(sf.ORDER_QNT)/31 as AVGPERDAY
FROM sales_fact sf,
date_dim dd
WHERE dd.date_id = sf.date_id
AND dd.MONTH_NUMBER = 1;
The question is, instead of putting 31, how can I get the total day of the month? and how can I apply that to the SELECT query. I'm pretty good with logic(c++), but this database is pretty new to me. I'm using Oracle 11g by the way. Thank you for any help.
The question is, instead of putting 31, how can I get the total day of the month?
Pick any one solution :
1.
You can add a month to a date and substract both the dates :
ADD_MONTHS(date_col, 1) - date_col
Example :
SQL> WITH dates AS(
2 SELECT to_date('05/01/13','mm/dd/rr') dt FROM dual UNION ALL
3 SELECT to_date('06/01/13','mm/dd/rr') dt FROM dual UNION ALL
4 SELECT to_date('02/01/13','mm/dd/rr') dt FROM dual)
5 SELECT ADD_MONTHS(dt, 1) - dt num_of_days_per_month
6 from dates
7 /
NUM_OF_DAYS_PER_MONTH
---------------------
31
30
28
Or,
You can extract the last day of the month :
EXTRACT(DAY FROM LAST_DAY (date_col))
Example :
SQL> WITH dates AS(
2 SELECT to_date('05/01/13','mm/dd/rr') dt FROM dual UNION ALL
3 SELECT to_date('06/01/13','mm/dd/rr') dt FROM dual UNION ALL
4 SELECT to_date('02/01/13','mm/dd/rr') dt FROM dual)
5 SELECT EXTRACT(DAY FROM LAST_DAY(dt)) num_of_days_per_month
6 from dates
7 /
NUM_OF_DAYS_PER_MONTH
---------------------
31
30
28