Oracle SQL Connect By Level - literal does not match format string - sql

I want to generate dates between 2 dates coming from parameters in oracle fusion using the connect by level statement
SELECT papf.person_number emp_id,
(SELECT to_date(:p_from_date,'dd-mm-yyyy') + level - 1 dt
from dual
connect by level <= (
to_date(:p_to_date,'dd-mm-yyyy') - to_date(:p_from_date,'dd-mm-yyyy') + 1
) ),
....
I get error ORA-01861: literal does not match format string, I tried to use to_char and change the format but doesn't work, the parameter date format is also dd-mm-yyyy, what is wrong here?

SELECT
dt --papf.person_number emp_id
FROM
(
SELECT to_date(:p_from_date,'dd-mm-yyyy') + level - 1 dt
FROM dual
connect by level <= to_date(:p_to_date,'dd-mm-yyyy') - to_date(:p_from_date,'dd-mm-yyyy') + 1) papf
Your inner query selects just the dt column, FROM was missing, brackets in wrong places... Anyway with variables bound as 01-01-2023 and 10-01-2023 the result is:
dt
----------
01-JAN-23
02-JAN-23
03-JAN-23
04-JAN-23
05-JAN-23
06-JAN-23
07-JAN-23
08-JAN-23
09-JAN-23
10-JAN-23
If your parameters are of DATE data type then
SELECT
To_Char(dt, 'dd-mm-yyyy') "DT"
FROM
(
SELECT :p_from_date + level - 1 dt
FROM dual
connect by level <= :p_to_date - :p_from_date + 1) papf
DT
----------
01-01-2023
02-01-2023
03-01-2023
04-01-2023
05-01-2023
06-01-2023
07-01-2023
08-01-2023
09-01-2023
10-01-2023

Related

to get only Saturdays between two dates in plsql

SELECT * FROM dummy;
act_date
---------
27-JAN-22
SELECT * FROM dummy1;
rpt_date
---------
10-JAN-22
10-DEC-21
how to get only Saturdays between act_date of dummy and MIN(rpt_date) of dummy1 table in Oracle's SQL?
please help
Here is a simple example of how to list all saturdays between 2 dates, you should be able to convert this to your data model.
WITH dummy(start_date, end_date) AS
(
SELECT DATE'2014-01-30', DATE'2014-02-25' FROM dual
), dummy_all_dates(dt) AS
(
SELECT
e.dt
FROM
dummy d CROSS APPLY
( SELECT
d.start_date + level - 1 AS dt
FROM dual CONNECT BY level < d.end_date - d.start_date
) e
)
SELECT dt FROM dummy_all_dates
WHERE TO_CHAR(dt,'FMDAY','NLS_DATE_LANGUAGE=english') = 'SATURDAY';
01-FEB-2014
08-FEB-2014
15-FEB-2014
22-FEB-2014
Here's another method to get a years worth of Saturdays. Adjust the dates as needed.
The to_char function has various format masks you can use to extract the day-of-week from a date. This uses day to get the full day name:
with rws as (
select date'2021-12-31' + level dt
from dual
connect by level <= (
date'2022-01-01' - date'2021-01-01'
)
)
select dt
from rws
where to_char (
dt,
'fmday',
'nls_date_language = English'
) = 'saturday';
This is the simplest of all answers:
select dt,rtrim(to_char(dt, 'DAY')) from (select to_date(SELECT
min(rpt_date)
FROM dummy1, 'DD-MON-YY') + rownum -1 dt
from all_objects
where rownum <= to_date((SELECT act_date FROM dummy), 'DD-MON-YY') -
to_date(SELECT min(rpt_date) FROM dummy1, 'DD-MON-YY'));
where rtrim(to_char(dt, 'DAY')) = 'SATURDAY';
Thanks!!

How to extract No. of Days between 2 dates in oracle sql?

I want No. of days between these 2 dates using Oracle SQL
Dates:
BETWEEN "1/1/2018" AND "6/11/2018"
How to write SQL Query?
between date '2018-01-01' and date '2018-11-06'
where DATE literal looks exactly like that: DATE 'YYYY-MM-DD'
In your example:
double quote's can't be used
even if you used single quotes, that would be a string, not DATE so you'd depend on whether Oracle is capable of converting it (implicitly) to date or not
therefore, always use dates, not strings
[EDIT]
This is how you select the whole calendar between those two dates:
select date '2018-01-01' + level - 1
from dual
connect by level <= date '2018-11-06' - date '2018-01-01' + 1;
As other answers have pointed out you can simply divide two dates, but there is also no need for any additional arithmetic.
The code:
select to_date('6/11/2018', 'DD/MM/YYYY') - to_date('1/1/2018', 'DD/MM/YYYY')
from dual;
The result: 309
you can simple do:
select date1-date2 form dual;
or
select (sysdate-to_date('01-jan-2018'))-(sysdate-to_date('10-jan-2018'))from dual;
Just use
select date'2018-11-06' - date'2018-01-01' + 1 as days_difference
from dual;
DAYS_DIFFERENCE
---------------
310
or
with t( myDate ) as
(
select date'2018-11-06' from dual union all
select date'2018-01-01' from dual
)
select max(myDate) - min(myDate) + 1 as days_difference
from t;
DAYS_DIFFERENCE
---------------
310

how to bind varible in sql/plsql

My query is
with dates_table as (
SELECT to_date(:begin_date, 'dd/mm/yyyy') + ROWNUM - 1 cal_day
FROM dual
CONNECT BY LEVEL <= to_date(:end_date, 'dd/mm/yyyy') - to_date(:begin_date, 'dd/mm/yyyy') + 1)
SELECT '1' AS ID,
'bank' AS DESC,
cal_day AS dates,
(SUM (
CASE
WHEN S_DATE BETWEEN ADD_MONTHS (cal_day, 0) - 13
AND ADD_MONTHS (cal_day, 0) - 7
THEN
VOLUME
ELSE
0
END))
LAST_14_days,
(SUM (
CASE
WHEN S_DATE BETWEEN ADD_MONTHS (cal_day, 0) - 6
AND ADD_MONTHS (cal_day, 0)
THEN
VOLUME
ELSE
0
END))
last 7day
FROM abc, day
where day.cal_day between '13-NOV-16' and '22-MAR-17'
group by cal_day
order by cal_day
you may replace you parametric sql in the upper part with the following :
SELECT to_date('&&begin_date', 'dd/mm/yyyy') + ROWNUM - 1 cal_day
FROM dual
CONNECT BY LEVEL <= to_date('&&end_date', 'dd/mm/yyyy') - to_date('&&begin_date', 'dd/mm/yyyy') + 1)
....
For numeric values you may directly define variables without single quotes'', but you should include quotes for date or string type parameters. In each case use double ampersand so that repeating parameters( you have more than one :begin_date ) don't prompt you(normally, you can use single ampersand also, but in this case you'll be prompted for each parameter even if they're the same )

Need to return sysdate and past 9 dates

With the code below I can return this month and past 6 months.
My code:
SELECT TO_CHAR(add_months(TRUNC(to_date( sysdate),'Month'), -rownum+1), 'Month') mon,
rownum month_order
FROM dual
CONNECT BY rownum <=
(SELECT COUNT(mon)
FROM
(SELECT TO_CHAR( add_months( start_date, level-1 ), 'fmMonth' ) AS mon
FROM
(SELECT to_date( add_months(TRUNC(sysdate),-6)) start_date,
to_date( sysdate) end_date
FROM dual)
CONNECT BY level <= months_between( TRUNC(end_date,'MM'), TRUNC(start_date,'MM') ) + 1) dual);
In the same way I have to return this date and past 9 dates.
Please help me on this to return 10 dates by using connect by.
Thanks in advance.
Here's a query for the last ten days.
select sysdate - (level-1)
, level as day_order
from dual
connect by level <= 10;
Your month query seems extremely over-engineered. This would do the same thing:
select to_char(add_months(trunc(sysdate, 'MM'), 1 - level), 'Month')
, level as month_order
from dual
connect by level <= 7;
"Let suppose if the data is available on today's date and remaining 9 date's doesn't have any data but it has to display the count as zero"
Use the generated result set in an outer join:
with q as (
select sysdate - (level-1) as dt
, level as day_order
from dual
connect by level <= 10
)
select q.dt as txn_date
, sum(t42.col1)
from q
left outer join t42
on t42.transaction_date = q.dt
group by q.dt;
Try this -
SELECT ( TRUNC( SYSDATE ) + 1 ) - ROWNUM
FROM DUAL
CONNECT BY ROWNUM <= 10
In the same way i have to return this date and past 9 dates.
This will get today and the past 9 days:
SELECT TRUNC( SYSDATE ) - LEVEL + 1 AS day
FROM DUAL
CONNECT BY LEVEL <= 10
this month and past 6 months
SELECT TO_CHAR( ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 1 - LEVEL ), 'Month' ) AS month
FROM DUAL
CONNECT BY LEVEL <= 7

Query which will give a list of dates between two date ranges

My question is similar to following question:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:14582643282111
The difference is my inner query returns two records and I have outer query.
I need to write inner query something like this which will give me a list of dates between two date ranges (I am trying this query whcih does not execute).
Select * from outerTable where my_date in
(
select to_date(r.REQ_DATE) + rownum -1
from all_objects, (MY_INNER_QUERY Where ID =100) r
where rownum <= to_date(r.DUE_DATE,'dd-mon-yyyy')-to_date(r.REQ_DATE,'dd-mon-yyyy')+1;
)
My inner query returns following 2 rows:
Select * from innerTable Where ID =100
Start date end date
3/19/2013 3/21/2013
3/8/2013 3/8/2013
So I am need inner query which will return following dates to outer query:
3/19/2013
3/20/2013
3/21/2013
3/8/2013
Great question - this one really drew me in! The answer was more or less buried further down on Tom's post. Here's the short version, using a table called TestDR to define the ranges. First the TestDR contents:
SELECT * FROM TestDR;
STARTDATE ENDDATE
--------- ---------
19-MAR-13 21-MAR-13
08-MAR-13 08-MAR-13
Now for the query to create one row for each date in the range:
WITH NUMS AS (
SELECT LEVEL-1 DaysToAdd
FROM DUAL
CONNECT BY LEVEL <= 60
)
SELECT StartDate + DaysToAdd TheDate
FROM TestDR
CROSS JOIN NUMS
WHERE TestDR.EndDate - TestDR.StartDate + 1 > DaysToAdd
ORDER BY 1
THEDATE
---------
08-MAR-13
19-MAR-13
20-MAR-13
21-MAR-13
With the query adapted from Tom's posting, you have to know the maximum range going in to "seed" the NUMS query. He used 60 in his example so that's what I used above. If you don't think any row from your subquery will ever have a range of more than 60 days then this will do the trick. If you think the maximum could be as much as 1000 days (about three years) then change the 60 to 1000. I tried this and queried a 2 1/2 year range and the results were instantaneous.
If you want to specify the exact "seed" count you can calculate it if you're willing to make the query a bit more complicated. Here's how I can do it with my TestDR table:
WITH NUMS AS (
SELECT LEVEL-1 DaysToAdd
FROM DUAL
CONNECT BY LEVEL <= (
SELECT MAX(EndDate - StartDate + 1)
FROM TestDR)
)
SELECT ... and the rest of the query as above
For your problem, you don't need to enumerate the dates. A simple JOIN suffices.
SELECT o.*
FROM outerTable o
INNER JOIN innerTable i
ON i.ID = 100
AND o.my_date BETWEEN i.REQ_DT and i.DUE_DT
From your code, I can tell that you must be a OO programmer and not familiar with SQL. It does a lot for you, so don't try to control it. It will hinder it's optimization features.
Don't take this in the wrong way, I had the same mindset (believing that I am smarter than the machine).
In your outer query use an OR statement, which allows your date to be equal to either the return Start_Date or End_Date
AND (date = subQuery.Start_Date
OR date = subQuery.End_Date)
Using your dates:
SELECT smth... FROM some_tab
WHERE your_date IN
( -- remove unnecessary columns, leave only what you select in outer query
-- or select *
SELECT start_date
, TRUNC(start_date, 'iw') wk_starts
, TRUNC(start_date, 'iw') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#
FROM
(
SELECT (start_date-1) + LEVEL AS start_date
FROM
( -- replace this part with selecting your start and end dates from your table --
SELECT to_date('03/21/2013', 'MM/DD/YYYY') end_date
, to_date('03/19/2013', 'MM/DD/YYYY') start_date
FROM dual
)
CONNECT BY LEVEL <= (end_date - start_date)
)
) -- your outer query ends --
/
START_DATE WK_STARTS WK_ENDS ISO_WK#
----------------------------------------------------------
3/19/2013 3/18/2013 3/24/2013 11:59:59 PM 12
3/20/2013 3/18/2013 3/24/2013 11:59:59 PM 12
Annual table of dates and ISO weeks etc... Use any dates for start and end dates. The connect by and number of days between is used to generate table on the fly. You may use between operator if using hard structures...:
SELECT start_date
, TRUNC(start_date, 'iw') wk_starts
, TRUNC(start_date, 'iw') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#
FROM
(-- This part simplifies above formatting and optional --
SELECT (start_date-1) + LEVEL AS start_date
FROM
(-- Replace start/end dated with any dates --
SELECT TRUNC(ADD_MONTHS (SYSDATE, 12), 'Y')-1 end_date
, TRUNC(SYSDATE, 'YEAR') start_date
FROM dual
)
CONNECT BY LEVEL <= (end_date - start_date) -- number of days between dates
)
/
START_DATE WK_STARTS WK_ENDS ISO_WK#
-----------------------------------------------------------
1/1/2013 12/31/2012 1/6/2013 11:59:59 PM 1
1/2/2013 12/31/2012 1/6/2013 11:59:59 PM 1
1/3/2013 12/31/2012 1/6/2013 11:59:59 PM 1
...
12/28/2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/29/2013 12/23/2013 12/29/2013 11:59:59 PM 52
12/30/2013 12/30/2013 1/5/2014 11:59:59 PM 1